EXCEPT & INTERSECT:逻辑计划中被动投射的目的

Pau*_*mes 9 sql-server optimization database-internals except

下面的 EXCEPT 查询生成一个带有看似无目的投影的逻辑计划。INTERSECT 也会发生这种情况。

投影的目的是什么?例如,是否有不同的 EXCEPT 查询,其中外投影会指定某些内容?

询问:

use AdventureWorks2017

select p.ProductId
from Production.Product as p
except
select pinv.ProductID
from Production.ProductInventory as pinv
option (recompile, querytraceon 8605, querytraceon 3604)
Run Code Online (Sandbox Code Playgroud)

转换树:

    LogOp_Select

        LogOp_GbAgg OUT(QCOL: [p].ProductID,) BY(QCOL: [p].ProductID,)

            LogOp_Project -- << ?? PASSIVE PROJECTION ??

                LogOp_Project

                    LogOp_Get TBL: Production.Product(alias TBL: p) Production.Product TableID=482100758 TableReferenceID=0 IsRow: COL: IsBaseRow1000 

                    AncOp_PrjList 

                AncOp_PrjList 

            AncOp_PrjList 

        ScaOp_Exists 

            LogOp_Select

                LogOp_Project

                    LogOp_Get TBL: Production.ProductInventory(alias TBL: pinv) Production.ProductInventory TableID=914102297 TableReferenceID=0 IsRow: COL: IsBaseRow1001 

                    AncOp_PrjList 

                ScaOp_Comp x_cmpEq

                    ScaOp_Identifier QCOL: [p].ProductID

                    ScaOp_Identifier QCOL: [pinv].ProductID
Run Code Online (Sandbox Code Playgroud)

Con*_*SFT 14

我们在查询优化器内部做的各种事情并没有我们可以在外部解释的真正原因。您在优化器中看到的项目最终会在优化器的末尾被重写以“扁平化”表达式。因此,优化器在搜索中有一些东西是代码实现方式的一部分,这些东西可能会引入额外的项目,这些项目实际上在功能上没有做任何事情,但允许我们将在优化器的一部分中创建一个子树的地方拼接在一起但后来在原本不打算使用的地方使用。有一些物理实现细节会导致这种情况发生。就计划质量而言,它们对用户都不重要(几乎在任何情况下 - 我们已经努力使这些在搜索中无关紧要)。

所以,我只是挥挥手说“你不需要看他的身份证明。他可以做他的事。继续前进”;)。


Pau*_*ite 11

我对此没有一个完全令人满意的答案,但DISTINCT被转换为一个项目加上分组聚合。

二者EXCEPTINTERSECT配有一个隐含的DISTINCT在第一表表达式。正是这DISTINCT一点导致树中的“空白”项目。它是无害的。

如果您将 a 写DISTINCT为等效的GROUP BY,您将看不到空白项目。项目出现在聚合之后:

SELECT DISTINCT P.ProductID
FROM Production.Product AS P
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);
Run Code Online (Sandbox Code Playgroud)
SELECT DISTINCT P.ProductID
FROM Production.Product AS P
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);
Run Code Online (Sandbox Code Playgroud)
SELECT P.ProductID
FROM Production.Product AS P
GROUP BY p.ProductID
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);
Run Code Online (Sandbox Code Playgroud)
LogOp_GbAgg OUT(QCOL: [P].ProductID,) BY(QCOL: [P].ProductID,)
    LogOp_Project
        LogOp_Project QCOL: [P].ProductID
            LogOp_Get TBL: Production.Product(alias TBL: P)
            AncOp_PrjList 
        AncOp_PrjList 
    AncOp_PrjList
Run Code Online (Sandbox Code Playgroud)

  • 是的,我们都有一些额外的 COVID 时间 :) 请接受康纳的回答。查询优化器的首席架构师并不是每天都会回答您的问题。 (6认同)