SQL Server 2017:交错执行如何工作?

Eri*_*ing 4 sql-server functions sql-server-2017 interleaved-execution

Interleaved Execution 是2017 查询处理器中一系列功能的一部分,其中包括:

那么交错执行是如何工作的呢?

Eri*_*ing 6

魔鬼在表变量中

交错执行旨在解决多语句表值函数中错误估计的正确基数。

在 SQL Server 的早期版本中,这些函数总是会产生相当粗劣的估计:

  • 2014、2016 年:100 行
  • 2005 - 2012 年:1 行

不用说,这在加入其他表时可能会导致很多问题。

虽然从表变量中选择数据本身不会抑制并行性,但低行估计通常会导致查询成本低,而并行性不会被考虑。

使用交错执行时,基数估计会暂停,MSTVF 的子树会被执行,并使用更准确的基数估计恢复优化。

我如何知道我的 MSTVF 是否接收交错执行。

与自适应连接一样,交错执行也在查询计划中注明。与 Adaptive Joins 不同,它没有在估计的计划中注明,至少在撰写本文时是这样。

具有交错执行的 MSTVF 的计划形状与其中包含 MSTVF 的典型计划略有不同。

您将看到计划顶部的表值函数运算符,以及 TVF 运算符通常位于图形计划中的表变量的扫描。

坚果

将鼠标悬停在 TVF 运算符上时,您将看到该属性IsInterleavedExecuted设置为 True,以及可能非常接近真实情况的估计行数。欢呼。

当不发生交错执行时,是否有任何扩展事件可以进行故障排除?

是的,一大堆:

坚果

请注意,其中一些位于调试通道中,在搜索要扩展的事件时默认情况下未选择该通道。

交错执行是否需要列存储索引?

不,无论哪种方式,它们都会起作用。下面是一个例子:

SELECT u.Id, mj.*
FROM   dbo.Users_cx AS u --ColumnStore
JOIN   dbo.MultiStatementTVF_Join(0) AS mj
ON mj.UserId = u.Id
WHERE  u.LastAccessDate >= '2016-12-01';


SELECT u.Id, mj.*
FROM   dbo.Users AS u --RowStore
JOIN   dbo.MultiStatementTVF_Join(0) AS mj
ON mj.UserId = u.Id
WHERE  u.LastAccessDate >= '2016-12-01';
Run Code Online (Sandbox Code Playgroud)

这些查询各自连接到不同的表。一个 ColumnStore,一个不是。他们都得到交错执行计划。

坚果

交错执行何时起作用?

目前,它仅适用于在函数之外完成关联的 MSTVF 。

这里有几个例子:

此函数没有内部相关性,这意味着WHERE在表列和传入变量上没有谓词的子句。

CREATE OR ALTER FUNCTION dbo.MultiStatementTVF_Join
(
    @h BIGINT
)
RETURNS @Out TABLE
(
    UserId INT,
    BadgeCount BIGINT
)
AS
    BEGIN
        INSERT INTO @Out ( UserId, BadgeCount )
        SELECT   b.UserId, COUNT_BIG(*) AS BadgeCount
        FROM     dbo.Badges AS b
        GROUP BY b.UserId
        HAVING   COUNT_BIG(*) > @h;
        RETURN;
    END;
GO
Run Code Online (Sandbox Code Playgroud)

这个函数是相反的,在UserId带有传入变量的列上有一个谓词。

CREATE OR ALTER FUNCTION dbo.MultiStatementTVF_CrossApply
(
    @h BIGINT,
    @id INT
)
RETURNS @Out TABLE
(
    UserId INT,
    BadgeCount BIGINT
)
AS
    BEGIN
        INSERT INTO @Out ( UserId, BadgeCount )
        SELECT   b.UserId, COUNT_BIG(*) AS BadgeCount
        FROM     dbo.Badges AS b
        WHERE    b.UserId = @id
        GROUP BY b.UserId
        HAVING   COUNT_BIG(*) > @h;
        RETURN;
    END;
GO
Run Code Online (Sandbox Code Playgroud)

这是CROSS APPLY行不通的常见误解。前面已经提到了真正的限制。内部函数相关性是交易破坏者。

SELECT u.Id, mj.*
FROM   dbo.Users AS u --RowStore
CROSS APPLY dbo.MultiStatementTVF_Join(0) AS mj
WHERE  mj.UserId = u.Id
       AND u.LastAccessDate >= '2016-12-01';


SELECT   TOP 1 u.Id, mj.*
FROM     dbo.Users AS u --RowStore
CROSS APPLY dbo.MultiStatementTVF_CrossApply(2147483647, u.Id) AS mj
WHERE    u.LastAccessDate >= '2016-12-01'
ORDER BY u.Id;
Run Code Online (Sandbox Code Playgroud)

坚果