我和一位老 DBA 一起工作,他说了很多奇怪的话。Dude 有一本 O'Reilly 的书,封面上只有一个变形虫。
午餐时我们讨论了并行性,因为我们的新服务器有 24 个内核。他说,在并行计划中,每个操作员都会获得 DOP 线程。因此,如果您有 MAXDOP 8 并且您的查询有 4 个并行运算符,它将同时使用 32 个线程。
这似乎不对,因为您很快就会用完线程。
我还读到整个查询可能只有 8 个,这似乎太少了。
为什么我在 sysprocesses 中看到每个 SPID 的线程多于 MAXDOP?
他们都对吗?
不,这充其量只是一种误导,但更接近于完全错误。
在串行计划中,每个操作员“获得”一个线程,但该线程对所有操作员来说都是同一个线程。并行计划的原理类似。
每个并行运算符都由
DOP
线程运行,但这些线程不是特定运算符独有的,它们在同一并行分支中的运算符之间共享。分支边界由并行运算符(Demand、Repartition 和 Gather Streams)分隔。下图显示了具有三个分支的并行计划:
转载自本答案末尾引用的文章
不。您不能只乘以
DOP
运算符的数量来获得线程数。为并行分支保留的线程数是并行分支数(不是运算符)乘以DOP
。DOP
在SQL Server 2005 及更高版本中,单个并行查询可以同时处于活动状态的线程数受到限制。SQL Server 通过将线程分配给DOP
调度程序来实现这一点。这
DOP = 8
对于具有单个并行分支的计划来说是正确的。一个并行计划中可以有多个并行计划分支。对于具有n
并行分支的计划,并行工作者的线程预留是n * DOP
.请参阅Paul White 的并行执行计划 - 分支和线程。
注意:执行计划中报告的分支数通常是可能并发执行的分支数(由于阻塞运算符,一个分支中的线程有时可能会安全地回收用于后面的分支)。
我所有的生产箱都在 SQL Server 2008(甚至不是 R2)上,没有钱升级。但是我得到了一个 3 CPU 的虚拟机,管理层不知道它隐藏了 SQL Server 2017 开发人员版(它是免费的!)。我对此进行了测试。
本周早些时候,我们的一位开发人员编写了很多 CROSS JOIN 查询,它们导致了一些问题,但我可以使用类似的查询来回答这个问题。开发人员做了这样的事情:
就像我说的那样,查询引起了各种警告警报,我不得不在半夜醒来。以下是我 2017 年“实例”的查询计划:
所以我得到了五个带有赛车箭头的操作员,这起初让我认为计划中有 5 个并行操作员。SQL Server 可能很棘手。nested loop join其实就是一个并行算子,所以一共有6个并行算子。如果查询 MAXDOP 为 3,如果它按照您的问题中描述的方式工作,我将获得 3 * 6 = 18 个工人。我可以查看实际计划的 XML 以找到以下内容:
这使得查询执行期间似乎只使用了 3 个线程。另外,我从互联网上获取了这个查询,并在执行 CROSS JOIN 查询时运行它:
它只显示 exec_context_id 值介于 0 和 3 之间的四行。因此,即使有许多并行运算符,这个查询也只使用了三个并行工作线程。确实,更复杂的查询可以使用比 MAXDOP 更多的工作器,但我认为可以肯定地说查询不会为每个并行运算符获得 MAXDOP 工作器。
更新:
我在互联网上找到了一个跟踪标志(不要在生产中使用!)并用它来获得另一个并行计划:
那个有六个并行工作线程!所以看起来不同模式的查询确实可以获得不同的工作线程,但它仍然不是每个操作员的 MAXDOP 线程。