การสแกนค่าคงที่และการเข้าร่วม Outer Left มาจากที่ใดในแผนคิวรี SELECT ที่สำคัญ


21

ฉันมีตารางนี้:

CREATE TABLE [dbo].[Accounts] (
    [AccountId] UNIQUEIDENTIFIER UNIQUE NOT NULL DEFAULT NEWID(),
    -- WHATEVER other columns
);
GO
CREATE UNIQUE CLUSTERED INDEX [AccountsIndex]
    ON [dbo].[Accounts]([AccountId] ASC);
GO

แบบสอบถามนี้:

DECLARE @result UNIQUEIDENTIFIER
SELECT @result = AccountId FROM Accounts WHERE AccountId='guid-here'

ดำเนินการกับแผนแบบสอบถามประกอบด้วยดัชนีแสวงหาเดียว - ตามที่คาดไว้:

SELECT <---- Clustered Index Seek

แบบสอบถามนี้ไม่เหมือนกัน:

DECLARE @result UNIQUEIDENTIFIER
SET @result = (SELECT AccountId FROM Accounts WHERE AccountId='guid-here')

แต่จะถูกดำเนินการด้วยแผนที่ผลลัพธ์ของดัชนีการค้นหาอยู่ด้านนอกเข้าร่วมกับผลลัพธ์ของการสแกนค่าคงที่และป้อนเข้าสู่การคำนวณสเกลาร์:

SELECT <--- Compute Scalar <--- Left Outer Join <--- Constant Scan
                                      ^
                                      |------Clustered Index Seek

เวทมนตร์พิเศษนั้นคืออะไร? ค่าคงที่สแกนตามด้วย Left Outer Join ทำอะไรได้บ้าง

คำตอบ:


29

ความหมายของทั้งสองประโยคนั้นแตกต่างกัน:

  • ตัวแรกไม่ได้ตั้งค่าของตัวแปรถ้าไม่พบแถว
  • ตัวที่สองตั้งค่าตัวแปรเสมอรวมถึง null ถ้าไม่พบแถว

การสแกนอย่างต่อเนื่องจะสร้างแถวว่าง (ไม่มีคอลัมน์!) ซึ่งจะส่งผลให้ตัวแปรมีการปรับปรุงในกรณีที่ไม่มีสิ่งใดที่ตรงกับจากตารางฐาน การเข้าร่วมด้านซ้ายช่วยให้แน่ใจว่าแถวว่างยังมีชีวิตอยู่การเข้าร่วม การกำหนดตัวแปรสามารถคิดได้ว่าเกิดขึ้นที่โหนดรูทของแผนการดำเนินการ

การใช้ SELECT @result

-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};

-- @result does not change
SELECT @result = AccountId 
FROM Accounts 
WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'};

SELECT @result;

ผล 1

การใช้ SET @result

-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};

-- @result set to null
SET @result = 
(
    SELECT AccountId 
    FROM Accounts 
    WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'}
);

SELECT @result;

ผล 2

แผนการดำเนินการ

เลือกที่ได้รับมอบหมายไม่มีแถวมาถึงโหนดรูทดังนั้นจึงไม่มีการกำหนดเกิดขึ้น

ตลาดหลักทรัพย์ฯแถวมาถึงที่โหนดรูตเสมอดังนั้นการกำหนดตัวแปรจึงเกิดขึ้น


การสแกนค่าคงที่พิเศษและลูปซ้อนด้านนอกด้านซ้ายเข้าร่วมไม่มีอะไรน่ากังวล การเข้าร่วมโดยเฉพาะราคาถูกเนื่องจากรับประกันว่าจะพบหนึ่งแถวในอินพุตภายนอกและอย่างน้อยหนึ่งแถว (ในตัวอย่างของคุณ) ในอินพุตภายใน

มีวิธีอื่น ๆ เพื่อให้แน่ใจว่าแถวถูกสร้างขึ้นจากแบบสอบถามย่อยเพื่อให้แน่ใจว่าการกำหนดตัวแปรเกิดขึ้น หนึ่งคือการใช้การรวมสเกลาร์ซ้ำซ้อน (ไม่มีกลุ่มตามข้อ):

-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};

-- @result set to null
SET @result = 
    (
        SELECT MAX(AccountId)
        FROM Accounts 
        WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'} 
    );
SELECT @result;

ผลที่ 3

แผนการดำเนินการรวมของเกลา

สังเกตว่าการรวมสเกลาร์จะสร้างแถวแม้ว่ามันจะไม่ได้รับอินพุตก็ตาม

เอกสารอ้างอิง:

หากคำสั่ง SELECT ไม่มีการส่งคืนแถวตัวแปรจะเก็บค่าปัจจุบันไว้ หากการแสดงออกเป็นแบบสอบถามย่อยสเกลาร์ที่ไม่ส่งคืนค่าใด ๆ ตัวแปรจะถูกตั้งค่าเป็น NULL

สำหรับการกำหนดตัวแปรเราขอแนะนำให้คุณใช้ SET @local_variable แทน SELECT @local_variable

อ่านเพิ่มเติม:

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