恒定扫描假脱机

i-o*_*one 14 sql-server execution-plan

我有一张有几十行的桌子。简化设置如下

CREATE TABLE #data ([Id] int, [Status] int);

INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);
Run Code Online (Sandbox Code Playgroud)

我有一个查询将这个表连接到一组表值构造的行(由变量和常量组成),比如

DECLARE @id1 int = 101, @id2 int = 105;

SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (@id1, 'A'),
        (@id2, 'B')
    ) p([Id], [Code])
    FULL JOIN #data d ON d.[Id] = p.[Id];
Run Code Online (Sandbox Code Playgroud)

查询执行计划显示优化器的决定是使用FULL LOOP JOIN策略,这似乎是合适的,因为两个输入都有很少的行。但是,我注意到(并且不能同意)的一件事是正在假脱机的 TVC 行(请参阅红色框中的执行计划区域)。

恒定扫描假脱机

为什么优化器在这里引入spool,这样做的原因是什么?除了线轴没有什么复杂的。看起来是没有必要的。在这种情况下如何摆脱它,可能的方法是什么?


上述计划获得于

Microsoft SQL Server 2014 (SP2-CU11) (KB4077063) - 12.0.5579.0 (X64)

Pau*_*ite 19

为什么优化器在这里引入spool,这样做的原因是什么?除了线轴没有什么复杂的。

线轴之外的东西不是简单的表引用,它可以在生成左连接/反半连接替代方案时简单地复制。

它可能看起来有点像一个表(常量扫描),但对于优化器*来说,它是子句中UNION ALL单独行的一个VALUES

额外的复杂性足以让优化器选择假脱机和重放源行,而不是稍后用简单的“表获取”替换假脱机。例如,完全连接的初始转换如下所示:

早期计划

请注意一般变换引入的额外线轴。简单表 get 上方的线轴稍后由规则清理SpoolGetToGet

如果优化器有相应的SpoolConstGetToConstGet规则,原则上它可以按您的意愿工作。

在这种情况下如何摆脱它,可能的方法是什么?

使用真实表(临时表或变量表),或手动编写从全连接的转换,例如:

WITH 
    p([Id], [Code]) AS
    (
        SELECT @id1, 'A'
        UNION ALL
        SELECT @id2, 'B'
    ),
    FullJoin AS
    (
        SELECT
            p.Code,
            d.[Status]
        FROM p
        LEFT JOIN #data d 
            ON d.[Id] = p.[Id]
        UNION ALL
        SELECT
            NULL,
            D.[Status]
        FROM #data AS D
        WHERE NOT EXISTS
        (
            SELECT *
            FROM p
            WHERE p.Id = D.Id
        )
    )
SELECT
    COALESCE(FullJoin.Code, 'X') AS Code,
    COALESCE(FullJoin.Status, 0) AS [Status]
FROM FullJoin;
Run Code Online (Sandbox Code Playgroud)

计划手动重写:

手动重写计划

这估计成本为 0.0067201 单位,而原始成本为 0.0203412 单位。


* 它可以LogOp_UnionAll转换后的树(TF 8605) 中观察到。在输入树(TF 8606) 中,它是一个LogOp_ConstTableGet. 该转换后的树示出了后解析,归一化,algebrization,装订,以及其他一些准备工作优化表达元件的树。的输入树示出了转换到否定范式(NNF转换),运行时间常数塌陷,和其他一些位和鲍勃后的元素。NNF 转换包括折叠逻辑联合和公共表获取等的逻辑。