SELECT *
FROM
(
SELECT TOP (1000)
u.Id
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u
OPTION(MAXDOP 1);
如果我运行这个查询(再次,DOP 1),计划会改变,内存授权会稍微增加。
SELECT *
FROM (
SELECT TOP (1000)
u.Id
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u
JOIN (
SELECT TOP (1000)
u.Id
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u2
ON u.Id = u2.Id
OPTION(MAXDOP 1);
SELECT *
FROM (
SELECT TOP (1000)
u.Id
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u
INNER LOOP JOIN ( --Force the loop join
SELECT TOP (1000)
u.Id
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u2
ON u.Id = u2.Id
OPTION(MAXDOP 1);
SELECT *
FROM
(
SELECT TOP (1000)
u.Id -- 166MB (INT)
, u.DisplayName -- 300MB (NVARCHAR 40)
, u.WebsiteUrl -- 900MB (NVARCHAR 200)
, u.Location -- 1.2GB (NVARCHAR 100)
, u.AboutMe -- 9GB (NVARCHAR MAX)
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u
OPTION(MAXDOP 1);
但是并行性呢?
如果我在不同的 DOP 上运行此查询,则内存授予不会乘以 DOP。
SELECT *
FROM (
SELECT TOP (1000)
u.Id
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u
INNER HASH JOIN (
SELECT TOP (1000)
u.Id
FROM dbo.Users AS u
ORDER BY u.Reputation
) AS u2
ON u.Id = u2.Id
ORDER BY u.Id, u2.Id -- Add an ORDER BY
OPTION(MAXDOP ?);
苏?
对于需要额外内存的 SQL Server 查询,授权是为串行计划派生的。如果探索和选择并行计划,内存将在线程之间平均分配。
内存授予估计基于:
如果选择了并行计划,则处理并行交换(分发、重新分发和收集流)会产生一些内存开销,但是它们的内存需求仍然不会以相同的方式计算。
消耗内存的运算符
最常见的请求内存的运算符是
需要内存的不太常见的运算符是插入列存储索引。它们的不同之处还在于,内存授权当前乘以 DOP。
排序的内存需求通常远高于散列。排序将要求至少估计内存授予的数据大小,因为它们需要按排序元素对所有结果列进行排序。哈希需要内存来构建哈希表,它不包括所有选定的列。
例子
如果我运行这个查询,故意提示 DOP 1,它将要求 166 MB 的内存。
如果我运行这个查询(再次,DOP 1),计划会改变,内存授权会稍微增加。
有两种排序,现在是哈希连接。内存授权稍微增加以适应哈希构建,但它不会加倍,因为排序运算符不能同时运行。
如果我更改查询以强制嵌套循环连接,则授权将加倍以处理并发排序。
内存授权加倍,因为 Nested Loop 不是阻塞运算符,而 Hash Join 是。
数据大小很重要
该查询选择不同组合的字符串数据。根据我选择的列,内存授予的大小会增加。
为可变字符串数据计算数据大小的方式是行 * 列声明长度的 50%。这对于 VARCHAR 和 NVARCHAR 是正确的,尽管 NVARCHAR 列是双倍的,因为它们存储双字节字符。在某些情况下,新的 CE 确实改变了这一点,但没有记录详细信息。
数据大小对于散列操作也很重要,但程度不如排序。
但是并行性呢?
如果我在不同的 DOP 上运行此查询,则内存授予不会乘以 DOP。
每个交换运算符处理更多的并行缓冲区略有增加,也许有内部原因,排序和哈希构建需要额外的内存来处理更高的 DOP,但这显然不是一个乘数。