永続化された計算列を選択すると、SQL Serverが「Compute Scalar」になるのはなぜですか?


21

SELECTこのコードの3つのステートメント

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が保持され、永続化されているにもかかわらず値が計算されます。
マーティンスミス

回答:


14

実験結果をコメントにまとめると、これは同じテーブルに2つの計算列があり、1 persistedつは保持されておらず、両方が同じ定義を持っている場合に発生するエッジケースのようです。

クエリの計画で

SELECT id5p
FROM dbo.persist_test;

テーブルスキャンpersist_testid列のみを出力します。次のスカラーは、スカラーを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マッチングを列順に(少なくともこの場合)が起こるように見えるように、データの永続化バージョンを読み取るのではなく、実行時に計算を行ってから満たされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.