web-dev-qa-db-ja.com

永続的な計算列をSELECTするとSQL Serverが「計算スカラー」になるのはなぜですか?

このコードの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;

この計画を生成します。

execution plan

永続的な値を選択している最後のSELECTCompute Scalar 演算子を生成するのはなぜですか?

21
Nick Chammas

コメントで実験的な結果を要約すると、これは同じテーブルに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のいずれかのリクエストは、実行時に計算を実行するのではなく、永続化されたバージョンのデータを読み取ることで満たされるため、列の順序で(少なくともこの場合は)マッチングが行われているように見えます。

14
Martin Smith