เหตุใด SQL Server“ Compute Scalar” เมื่อฉันเลือกคอลัมน์ที่คำนวณยังคงอยู่


21

สาม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ซึ่งเลือกค่าที่มีอยู่สร้างผู้ดำเนินการคำนวณสเกลาร์


3
ดูคำตอบของ @ SqlKiwi ที่นี่: ทำไมแผนปฏิบัติการถึงมีการเรียกใช้ฟังก์ชันที่ผู้ใช้กำหนดสำหรับคอลัมน์ที่คำนวณซึ่งยังคงอยู่ . ในแบบสอบถามของคุณรายการคอลัมน์ผลลัพธ์จากตารางเป็นเพียง[tempdb].[dbo].[persist_test].idและจะคำนวณค่าแม้จะยังคงอยู่
Martin Smith

คำตอบ:


14

เพียงเพื่อสรุปผลการทดลองในความคิดเห็นซึ่งเป็นกรณีขอบที่เกิดขึ้นเมื่อคุณมีคอลัมน์ที่คำนวณสองคอลัมน์ในตารางเดียวกันหนึ่งpersistedและคอลัมน์หนึ่งที่ไม่ยืนยันและทั้งสองมีนิยามเดียวกัน

ในแผนสำหรับแบบสอบถาม

SELECT id5p
FROM dbo.persist_test;

การสแกนตารางpersist_testจะปล่อยเฉพาะidคอลัมน์ สเกลาร์การคำนวณถัดไปพร้อมกับคูณด้วย 5 และส่งออกคอลัมน์ที่เรียกว่าid5แม้ว่าคอลัมน์นี้จะไม่ได้อ้างถึงในแบบสอบถาม เกลาคำนวณสุดท้ายพร้อมใช้เวลาค่าของและผลที่เป็นคอลัมน์ที่เรียกว่าid5id5p

การใช้แฟล็กการติดตามที่อธิบายใน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จะพอใจจากการอ่านข้อมูลที่เก็บไว้แทนการคำนวณที่รันไทม์ดังนั้นการจับคู่จะเกิดขึ้น (อย่างน้อยในกรณีนี้) ตามลำดับคอลัมน์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.