Eri*_*ing 3 sql-server sql-server-2017 memory-grant-feedback
批处理模式内存授予反馈是2017 查询处理器中一系列功能的一部分,其中包括:
那么批处理模式内存授予反馈是如何工作的呢?
什么是内存授予反馈?
批处理模式内存授予反馈尝试为查询调整适当大小的内存授予,纠正高估和低估。
当运行需要内存授权的查询时,优化器将请求一个它认为将所有行操作保留在内存中的大小的授权。
通常需要内存授权的事情:
当请求和授予过多内存时,并发性可能会受到影响。内存是一种有限资源,并不是所有东西都能一直使用它。没有无限制访问此类资源之类的东西。
当请求的内存太少时,查询可能会溢出到磁盘。看,没有人希望他们的查询随处可见。磁盘是可怕的。
魔法是如何运作的?
当需要内存授予的计划执行并被缓存时,将重新计算运行该计划所需的实际内存,并相应地更新计划信息。现在,它需要一个 ColumnStore 索引来实现批处理执行模式。
如果魔法不那么神奇呢?
此功能确实有一个终止点,它将回退到原始内存授予。如果运行需要不断重新计算的查询,我们的神奇功能将放弃。最终。在撰写本文时,我还没有关于何时退出的所有实现细节。
我怎么知道它是否有效?
您可以使用扩展事件:
您还可以在实际执行计划中多次运行的常规查询调整期间观察到它。
你能给我举个例子吗?
当然!这是一个存储过程。在正确的情况下,它会要求不正确的内存授予。
CREATE OR ALTER PROCEDURE dbo.LargeUnusedGrant (@OwnerUserId INT)
AS
BEGIN
SELECT TOP 200 *
FROM dbo.Posts_cx AS p
WHERE p.OwnerUserId = @OwnerUserId
AND p.PostTypeId = 1
ORDER BY p.Score DESC, p.Id DESC;
END;
GO
Run Code Online (Sandbox Code Playgroud)
查询计划在选择运算符上有警告。
真是悲哀!我们的查询要求太多内存。
在第二次执行时,警告将消失。
我听说过一些狡猾的把戏……
Itzik Ben-Gan和Niko Neugebauer都为需要批处理模式执行的功能和运算符提出了解决方法。
WHERE
包含 0 行的子句创建过滤的、非聚集的 ColumnStore 索引这两种方法都是有效的解决方法,可以让它发挥作用!
创建一个空的非聚集 ColumnStore 索引:
/*Itzik's Trizik*/
CREATE NONCLUSTERED COLUMNSTORE INDEX ncci_helper
ON dbo.Posts
(
Id,
AcceptedAnswerId,
AnswerCount,
ClosedDate,
CommentCount,
CommunityOwnedDate,
CreationDate,
FavoriteCount,
LastActivityDate,
LastEditDate,
LastEditorDisplayName,
LastEditorUserId,
OwnerUserId,
ParentId,
PostTypeId,
Score,
ViewCount,
IsHot )
WHERE ( Id = -2147483647 AND Id = 2147483647) -- eez impossible!
Run Code Online (Sandbox Code Playgroud)
对具有空索引的表运行不同版本的 proc:
CREATE OR ALTER PROCEDURE dbo.LargeUnusedGrant_alt1 (@OwnerUserId INT)
AS
BEGIN
SELECT TOP 200 *
FROM dbo.Posts AS p
WHERE p.OwnerUserId = @OwnerUserId
AND p.PostTypeId = 1
ORDER BY p.Score DESC, p.Id DESC;
END;
GO
Run Code Online (Sandbox Code Playgroud)
使用相同的值:
EXEC dbo.LargeUnusedGrant_alt1 @OwnerUserId = 8672;
GO
Run Code Online (Sandbox Code Playgroud)
首次运行:悲伤的记忆授予
第二轮:快乐记忆补助
多余的左连接:
/*Niko's Triko*/
CREATE OR ALTER PROCEDURE dbo.LargeUnusedGrant_alt2 (@OwnerUserId INT)
AS
BEGIN
CREATE TABLE #t1 (Id INT, INDEX cx_whatever CLUSTERED COLUMNSTORE);
SELECT TOP 200 *
FROM dbo.Posts AS p
LEFT JOIN #t1 ON 1 = 1
WHERE p.OwnerUserId = @OwnerUserId
AND p.PostTypeId = 1
ORDER BY p.Score DESC, p.Id DESC;
END;
GO
EXEC dbo.LargeUnusedGrant_alt2 @OwnerUserId = 8672;
GO
Run Code Online (Sandbox Code Playgroud)
首次运行:悲伤的记忆授予
第二轮:快乐记忆补助