SQL Server 批处理或任务计划

每个 SQL Server 实例都是一个单独的操作系统进程。每个实例都必须处理潜在的成千上万个并发用户请求。SQL Server 实例使用 Microsoft Windows 线程(如果经过配置,则使用纤程)来有效地管理这些并发任务。每个 SQL Server 实例始终运行系统进程的几个线程。这包括每个服务器 Net-Library 的一个或多个线程、处理网络 I/O 的网络线程以及用来与服务控制管理器通信的信号线程。

了解计划

每个 SQL Server 实例都有一个内部层,用来实现与操作系统类似的环境。这个内部层用于计划和同步并发任务,而不需调用 Windows 内核。此内部层还可以有效地计划纤程或 Windows 线程。每个 SQL Server 实例都维护一个 Windows 线程池或纤程池以处理用户查询。该池的最大大小由 max worker threads 服务器配置选项控制。

了解下列基本术语对了解如何处理请求或任务很有帮助:

  • 连接
    当用户成功登录时,就建立了连接。用户随后可以提交一个或多个 Transact-SQL 语句以完成执行。当用户显式注销或连接终止时,连接就关闭。

  • 批处理
    SQL 批处理是一个或多个 Transact-SQL 语句的集合,由客户端发送到 SQL Server 实例以完成执行。它表示用户提交给数据库引擎的工作单元。

  • 任务
    任务表示 SQL Server 计划的工作单元。一个批处理可映射到一个或多个任务。例如,一个并行查询可由多个任务执行。

  • Windows 线程
    每个 Windows 线程表示一个独立的执行机制。

  • 纤程
    纤程是轻型线程,它需要的资源比 Windows 线程少,而且可以在用户模式下切换上下文。一个 Windows 线程可映射到多个纤程。

  • 工作线程
    工作线程表示 SQL Server 中的逻辑线程,从内部映射 (1:1) 到 Windows 线程或纤程(如果打开了轻型池)。这种映射关系将一直保持,直到由于内存压力或长时间空闲而释放工作线程。任务与工作线程的关联将在任务的生命期内一直保持。

管理用户连接和工作线程资源

虽然线程和纤程在使用资源方面无足轻重,但它们仍要消耗资源。在具有成百上千个用户连接的系统中,为每个连接分配一个工作线程所消耗的资源足以降低 SQL Server 的效率。而且,没有必要为每个用户连接分配一个专用的工作线程,因为大多数连接的大量时间实际上都花在等待从客户端接收批处理上。相反,SQL Server 实例使用工作线程池。工作线程池的大小只要能够为该实例中同时执行批处理的用户连接服务就足够了。保留 max worker threads 选项的默认值 0 可以使 SQL Server 实例有效地将用户连接映射到多个工作线程。这可以确保用户连接不会消耗太多的资源。

为纤程配置 SQL Server

服务器配置选项 lightweight pooling 控制 SQL Server 实例是使用 Windows 线程还是纤程。此选项的默认值为 0。这表示 SQL Server 实例为每个工作线程计划一个 Windows 线程,工作线程数不超过 max worker threads 选项中设置的值。如果 lightweight pooling 设置为 1,SQL Server 将使用纤程而不是 Windows 线程。这称为在纤程模式下运行。在纤程模式下,SQL Server 实例为每个 SQL 计划程序分配一个 Windows 线程,然后为每个工作线程分配一个纤程,工作线程数不超过 max worker threads 选项中设置的值。SQL Server 实例使用 Windows 线程或纤程时使用相同的算法计划和同步任务。SQL Server Express 不支持纤程。有关详细信息,请参阅使用 lightweight pooling 选项。我们建议您不要使用纤程模式计划日常操作。这是因为它会抑制上下文切换优点的正常发挥,从而降低性能,并且因为 SQL Server 的某些组件在纤程模式下不能正常工作。有关详细信息,请参阅 lightweight pooling

批处理或任务计划的工作原理

当应用程序连接到数据库引擎时,将为其分配一个会话 ID (SPID)。在连接的生存期需要维护的所有信息都在与 SPID 相关的内部数据结构中进行管理。当 SQL Server 实例从客户端收到批处理时,它将批处理分解成一个或多个任务,然后将每个任务与工作线程池中可用的工作线程关联。工作线程在任务的生命期内都与该任务绑定在一起。工作线程将运行关联的 SQL 计划程序中的请求。如果没有可用的工作线程,且未达到 max worker threads 值,SQL Server 实例将为新批处理分配一个新的工作线程。如果没有可用的线程或纤程,但已达到 max worker threads 值,SQL Server 实例将阻止新任务,直到释放工作线程。

工作线程与任务关联后,它将一直保持与任务的关联直到结束,例如,直到批处理生成的最后一个结果集返回到客户端。此时,工作线程被释放,可以分配给与下一个批处理关联的任务。

只在从收到批处理到将结果返回到客户端这段时间内,数据库引擎才需要全力为连接执行任务。在此期间,可能有一段时间不需要处理批处理。例如,当数据库引擎必须等待读取操作检索当前查询所需的数据,或等待另一个批处理释放锁时,可能会出现这种情况。即使任务被阻止访问某些资源,任务与工作线程的关联也会得到维护。

只要数据库引擎开始处理与批处理关联的任务,就会计划让与该任务关联的工作线程来执行这项工作。当工作线程完成该任务的工作后,SQL Server 实例将把该工作线程分配给下一个准备工作的任务。在连接的生命期内,连接的 SPID 保持不变。长时间运行的连接的各个批处理任务可由多个不同的工作线程执行。例如,第一个批处理中的任务可由 worker1 执行,第二个批处理中的任务可由 worker2 执行。有些语句可以并行处理。在这种情况下,一个批处理的多个任务可以由多个工作线程同时执行。