在 SQL Server 中,是每个运算符的并行性还是其他什么?

Wor*_*SQL 7 sql-server parallelism

我和一个非常老的 DBA 一起工作,他说了很多奇怪的话。Dude 有一本 O'Reilly 的书,封面上只有一个变形虫。

午餐时我们讨论了并行性,因为我们的新服务器有 24 个内核。他说,在并行计划中,每个操作员都会获得 DOP 线程。因此,如果您有 MAXDOP 8 并且您的查询有 4 个并行运算符,它将一次使用 32 个线程。

这似乎不对,因为您会很快用完线程。

我还读到整个查询可能只有 8 个,这似乎太少了。

为什么我在 sysprocesses 中看到每个 SPID 的线程数比 MAXDOP 多?

他们中的任何一个都正确吗?

Pau*_*ite 15

他说,在并行计划中,每个操作员都会获得 DOP 线程。

不。这充其量只是误导,但更接近于完全错误。

在串行计划中,每个操作员“获得”一个线程,但该线程对于所有操作员来说都是同一个线程。并行计划的原理类似。

每个并行运算符都由 DOP线程运行,但这些线程并不专属于特定的运算符,它们在同一并行分支内的运算符之间共享

分支边界由并行操作符(Demand、Repartition 和 Gather Streams)定界。下图显示了具有三个分支的并行计划:

在此处输入图片说明 转载自本答案末尾引用的文章


因此,如果您有MAXDOP 8并且您的查询有 4 个并行运算符,它将一次使用 32 个线程。

没有。您不能仅乘以DOP运算符的数量来获得线程数。为并行分支保留的线程数是并行分支(不是运算符)的数量乘以DOP

DOPSQL Server 2005 和更高版本中,单个并行查询可以同时处于活动状态的线程数限制为。SQL Server 通过将线程分配给DOP调度程序来实现这一点。


我还读到整个查询可能只有 8 个,这似乎太少了。

DOP = 8这将是一个单一的并联支路计划是正确的。一个并行计划中可以有多个并行计划分支。对于具有n并行分支的计划,并行工作程序的线程预留为n * DOP

请参阅Paul White 的并行执行计划 – 分支和线程

注意:执行计划中报告的分支数通常是可能并发执行的分支数(由于阻塞运算符,一个分支中的线程有时可能会被安全地回收到后面的分支)。


rel*_*dba 5

我所有的生产机器都在 SQL Server 2008(甚至不是 R2)上,而且没有钱升级。但我得到了一个管理层不知道的 3 CPU 虚拟机,其中隐藏着 SQL Server 2017 开发人员版(它是免费的!)。我对此做了测试。

本周早些时候,我们的一位开发人员编写了很多 CROSS JOIN 查询,它们引起了一些问题,但我可以使用类似的查询来主要回答这个问题。开发者做了这样的事情:

SELECT MIN(t1.high + t2.high)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 3);
Run Code Online (Sandbox Code Playgroud)

就像我说的,这个查询引起了各种警告警报,我不得不在半夜醒来。以下是我的 2017 年“实例”上的查询计划:

在此输入图像描述

所以我有五个带有赛车箭头的操作员,这首先让我认为计划中有 5 个并行的操作员。但 SQL Server 可能会很棘手。嵌套循环连接实际上是一个并行运算符,因此总共有 6 个并行运算符。如果查询 MAXDOP 为 3,如果它按照问题中描述的方式工作,我将得到 3 * 6 = 18 个工作人员。我可以在实际计划的 XML 中查找以下内容:

      <QueryPlan DegreeOfParallelism="3" MemoryGrant="56" CachedPlanSize="32" CompileTime="3" CompileCPU="3" CompileMemory="272">
        <ThreadStat Branches="1" UsedThreads="3">
          <ThreadReservation NodeId="0" ReservedThreads="3" />
        </ThreadStat>
Run Code Online (Sandbox Code Playgroud)

这使得查询执行期间看起来只使用了 3 个线程。另外,我从互联网上获取了此查询,并在执行 CROSS JOIN 查询时运行它:

SELECT *
FROM sys.dm_os_tasks d
INNER JOIN sys.dm_exec_sessions s ON d.session_id = s.session_id
WHERE s.is_user_process = 1 AND s.session_id <> @@SPID;
Run Code Online (Sandbox Code Playgroud)

它仅显示 exec_context_id 值在 0 到 3 之间的四行。因此,即使有许多并行运算符,该查询也仅使用了三个并行工作线程。确实,更复杂的查询可以使用比 MAXDOP 更多的工作线程,但我认为可以肯定地说,查询不会为每个并行运算符获取 MAXDOP 工作线程。

更新:

我在互联网上找到了一个跟踪标志(不要在生产中使用!)并用它来获取另一个并行计划:

在此输入图像描述

那一个有六个并行工作线程!所以看起来不同模式的查询确实可以获得不同的工作线程,但它仍然不是每个运算符的 MAXDOP 线程。