Mengapa SQL Server "Menghitung Skalar" ketika saya PILIH kolom yang tetap dihitung?

21

Tiga SELECTpernyataan dalam kode ini

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;

buat rencana ini:

rencana eksekusi

Mengapa final SELECT, yang memilih nilai yang bertahan, menghasilkan operator Compute Scalar ?

Nick Chammas
sumber
3
Lihat jawaban @ SqlKiwi di sini: Mengapa Rencana Eksekusi menyertakan panggilan fungsi yang ditentukan pengguna untuk kolom yang dihitung yang tetap ada? . Dalam kueri Anda, daftar kolom output dari tabel hanya [tempdb].[dbo].[persist_test].iddan menghitung nilai meskipun tetap ada.
Martin Smith

Jawaban:

14

Hanya untuk meringkas temuan eksperimental dalam komentar ini tampaknya menjadi kasus tepi yang terjadi ketika Anda memiliki dua kolom yang dihitung dalam tabel yang sama, satu persisteddan satu tidak bertahan dan keduanya memiliki definisi yang sama.

Dalam rencana kueri

SELECT id5p
FROM dbo.persist_test;

Tabel memindai pada persist_testhanya memancarkan idkolom. Komputasi skalar berikutnya bersama mengalikan bahwa dengan 5 dan menghasilkan kolom yang disebut id5meskipun fakta bahwa kolom ini bahkan tidak direferensikan dalam kueri. Skalar komputasi akhir sepanjang mengambil nilai id5dan output yang disebut kolom id5p.

Menggunakan tanda jejak yang dijelaskan dalam Penyelidikan Dalam Query Optimizer - Bagian 2 (penafian: tanda ini tidak berdokumen / tidak didukung) dan melihat kueri

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

Memberikan hasilnya

Pohon Sebelum Normalisasi Proyek

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)

Pohon Setelah Normalisasi Proyek

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

Jadi tampak bahwa semua definisi kolom yang dihitung diperluas kemudian selama tahap Normalisasi Proyek semua ekspresi yang identik dicocokkan kembali ke kolom yang dihitung dan kebetulan cocok dengan id5dalam kasus ini. yaitu tidak memberikan preferensi ke persistedkolom.

Jika tabel dibuat kembali dengan definisi berikut

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

Kemudian permintaan untuk salah satu id5atau id5pakan puas dari membaca versi data yang bertahan daripada melakukan perhitungan saat runtime sehingga pencocokan tampaknya terjadi (setidaknya dalam kasus ini) dalam urutan kolom.

Martin Smith
sumber