このコードの3つの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
が Compute Scalar 演算子を生成するのはなぜですか?
コメントで実験的な結果を要約すると、これは同じテーブルに2つの計算された列があり、1つはpersisted
で、もう1つは永続化されておらず、どちらも同じ定義である場合に発生するEdgeケースのようです。
クエリの計画
SELECT id5p
FROM dbo.persist_test;
persist_test
でのテーブルスキャンでは、id
列のみが出力されます。次の計算スカラーは、5を乗算してid5
という列を出力しますが、この列はクエリで参照されていません。最後の計算スカラーはid5
の値を取り、id5p
という列として出力します。
クエリオプティマイザーの詳細–パート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
のいずれかのリクエストは、実行時に計算を実行するのではなく、永続化されたバージョンのデータを読み取ることで満たされるため、列の順序で(少なくともこの場合は)マッチングが行われているように見えます。