仅在评论中总结实验结果,这似乎是一种极端情况,当您在同一表中有两个计算列,一个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
因此匹配似乎按列顺序发生(至少在这种情况下)。
[tempdb].[dbo].[persist_test].id
尽管它被保留,但仍会计算该值。