当我选择一个持久化的计算列时,为什么SQL Server会“计算标量”?


21

SELECT此代码中的三个语句

USE [tempdb];
GO

SET NOCOUNT ON;

CREATE TABLE dbo.persist_test (
      id            INT NOT NULL
    , id5           AS (id * 5)
    , id5p          AS (id * 5) PERSISTED
);

INSERT INTO dbo.persist_test (id)
VALUES (1), (2), (3);

SELECT id
FROM dbo.persist_test;

SELECT id5
FROM dbo.persist_test;

SELECT id5p
FROM dbo.persist_test;

DROP TABLE dbo.persist_test;

生成此计划:

执行计划

为什么SELECT选择持久化值的final会生成Compute Scalar运算符?


3
请参见@SqlKiwi的答案:执行计划为什么要对持久化的计算列包括用户定义的函数调用?。在您的查询中,表中的输出列列表仅为该列表,[tempdb].[dbo].[persist_test].id尽管它被保留,但仍会计算该值。
Martin Smith

Answers:


14

仅在评论中总结实验结果,这似乎是一种极端情况,当您在同一表中有两个计算列,一个persisted和一个未持久并且它们都具有相同的定义时,就会发生这种情况。

在查询计划中

SELECT id5p
FROM dbo.persist_test;

进行表扫描persist_test仅发出该id列。下一个计算标量将其乘以5并输出一个称为的列,id5尽管该列甚至没有在查询中引用。最终的计算标量沿着取值id5并将其输出为称为id5p

使用Query Optimizer Deep Dive –第2部分(免责声明:这些跟踪标志未记录/不受支持)中说明的跟踪标志并查看查询

SELECT id5,
       id5p,
       ( id * 5 )
FROM   dbo.persist_test 
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8606);

给出输出

项目规范化之前的树

LogOp_Project

    LogOp_Get TBL: dbo.persist_test dbo.persist_test TableID=1717581157 TableReferenceID=0 IsRow: COL: IsBaseRow1002 

    AncOp_PrjList 

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5

            ScaOp_Arithmetic x_aopMult

                ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id

                ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=5)

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5p

            ScaOp_Arithmetic x_aopMult

                ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id

                ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=5)

        AncOp_PrjEl COL: Expr1004 

            ScaOp_Arithmetic x_aopMult

                ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id

                ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=5)

项目规范化后的树

LogOp_Project

    LogOp_Get TBL: dbo.persist_test dbo.persist_test TableID=1717581157 TableReferenceID=0 IsRow: COL: IsBaseRow1002 

    AncOp_PrjList 

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5

            ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id5

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5p

            ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id5

        AncOp_PrjEl COL: Expr1004 

            ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id5

因此,似乎所有计算出的列定义都被扩展了,然后在项目规范化阶段,所有相同的表达式都被匹配回计算出的列,并且恰好匹配 id5在这种情况下。即,它不给予任何偏爱persisted列。

如果使用以下定义重新创建表

CREATE TABLE dbo.persist_test (
      id            INT NOT NULL
    , id5p          AS (5 * id) PERSISTED
    , id5           AS (5 * id)
);

然后,通过读取数据的持久版本而不是在运行时进行计算即可满足对id5或的请求,id5p因此匹配似乎按列顺序发生(至少在这种情况下)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.