เหตุใดตัวแปรตารางบังคับให้สแกนดัชนีในขณะที่ตาราง temp ใช้การค้นหาและคั่นหน้าการค้นหา


18

ฉันพยายามที่จะเข้าใจว่าทำไมการใช้ตัวแปรตารางทำให้เครื่องมือเพิ่มประสิทธิภาพไม่สามารถใช้การค้นหาดัชนีจากนั้นทำบุ๊กมาร์กการค้นหากับการสแกนดัชนี

การเติมตาราง:

CREATE TABLE dbo.Test 
(
    RowKey INT NOT NULL PRIMARY KEY, 
    SecondColumn CHAR(1) NOT NULL DEFAULT 'x',
    ForeignKey INT NOT NULL 
) 

INSERT dbo.Test 
(
    RowKey, 
    ForeignKey
) 
SELECT TOP 1000000 
    ROW_NUMBER() OVER (ORDER BY (SELECT 0)),
    ABS(CHECKSUM(NEWID()) % 10)     
FROM sys.all_objects s1
CROSS JOIN sys.all_objects s2 

CREATE INDEX ix_Test_1 ON dbo.Test (ForeignKey) 

เติมตัวแปรตารางด้วยเรกคอร์ดเดียวและพยายามค้นหาคีย์หลักและคอลัมน์ที่สองโดยค้นหาในคอลัมน์คีย์ต่างประเทศ:

DECLARE @Keys TABLE (RowKey INT NOT NULL) 

INSERT @Keys (RowKey) VALUES (10)

SELECT 
    t.RowKey,
    t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    @Keys k
ON
    t.ForeignKey = k.RowKey

ด้านล่างเป็นแผนการดำเนินการ:

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้แบบสอบถามเดียวกันโดยใช้ตาราง temp แทน:

CREATE TABLE #Keys (RowKey INT NOT NULL) 

INSERT #Keys (RowKey) VALUES (10) 

SELECT 
    t.RowKey,
    t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    #Keys k
ON
    t.ForeignKey = k.RowKey

แผนคิวรีนี้ใช้การค้นหาขอและคั่นหน้า:

ป้อนคำอธิบายรูปภาพที่นี่

เหตุใดเครื่องมือเพิ่มประสิทธิภาพจึงยินดีทำการค้นหาบุ๊กมาร์กด้วยตาราง temp แต่ไม่ใช่ตัวแปรตาราง

ตัวแปรตารางถูกใช้ในตัวอย่างนี้เพื่อแสดงข้อมูลที่ผ่านประเภทตารางที่ผู้ใช้กำหนดในขั้นตอนการจัดเก็บ

ฉันรู้ว่าการค้นหาดัชนีอาจไม่เหมาะสมหากค่าคีย์ต่างประเทศเกิดขึ้นหลายแสนครั้ง ในกรณีนั้นการสแกนอาจเป็นตัวเลือกที่ดีกว่า สำหรับสถานการณ์ที่ฉันสร้างขึ้นไม่มีแถวที่มีค่าเท่ากับ 10 ฉันยังคิดว่าพฤติกรรมน่าสนใจและอยากทราบว่ามีเหตุผลหรือไม่

ซอ Fiddle

การเพิ่มOPTION (RECOMPILE)ไม่ได้เปลี่ยนพฤติกรรม UDDT มีคีย์หลัก

@@VERSION คือ SQL Server 2008 R2 (SP2) - 10.50.4042.0 (X64) (รุ่น 7601: Service Pack 1) (Hypervisor)

คำตอบ:


15

สาเหตุของพฤติกรรมคือ SQL Server ไม่สามารถกำหนดจำนวนแถวที่จะตรงกับ ForeignKey ได้เนื่องจากไม่มีดัชนีที่มี RowKey เป็นคอลัมน์นำ (สามารถสรุปได้จากสถิติในตาราง #temp มีอยู่สำหรับตัวแปรตาราง / UDTT) ดังนั้นจึงทำการประมาณ 100,000 แถวซึ่งสามารถจัดการกับการสแกนได้ดีกว่าการค้นหา + การค้นหา เมื่อถึงเวลาที่ SQL Server พบว่ามีเพียงแถวเดียวมันก็สายเกินไป

คุณอาจสร้าง UDTT ของคุณแตกต่างออกไป ใน SQL Server รุ่นที่ทันสมัยกว่าคุณสามารถสร้างดัชนีรองบนตัวแปรตารางได้ แต่ไวยากรณ์นี้ไม่พร้อมใช้งานในปี 2008 R2

BTW คุณจะได้รับพฤติกรรมการค้นหา (อย่างน้อยในการทดลองที่ จำกัด ของฉัน) ถ้าคุณพยายามหลีกเลี่ยงบิตแมป / โพรบด้วยการบอกกล่าวลูปซ้อนกัน:

DECLARE @Keys TABLE (RowKey INT PRIMARY KEY); -- can't hurt

INSERT @Keys (RowKey) VALUES (10);

SELECT 
     t.RowKey
    ,t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    @Keys k
ON
    t.ForeignKey = k.RowKey
    OPTION (LOOP JOIN);

ฉันเรียนรู้เคล็ดลับนี้จาก Paul White เมื่อหลายปีก่อน แน่นอนคุณควรระมัดระวังเกี่ยวกับการใส่คำแนะนำการเข้าร่วมใด ๆ ในรหัสการผลิตซึ่งอาจล้มเหลวได้หากผู้คนทำการเปลี่ยนแปลงวัตถุพื้นฐานและการเข้าร่วมประเภทนั้นเป็นไปไม่ได้อีกต่อไปหรือไม่เหมาะสมที่สุดอีกต่อไป

สำหรับแบบสอบถามที่ซับซ้อนมากขึ้นและเมื่อคุณย้ายไปยัง SQL Server 2012 หรือสูงกว่าอาจเป็นไปได้ว่าการตั้งค่าสถานะการสืบค้นกลับ 2453สามารถช่วยได้ แต่ธงนั้นไม่ได้ช่วยในการเข้าร่วมแบบง่าย ๆ นี้ และจะมีการปฏิเสธความรับผิดชอบแบบเดียวกัน - นี่เป็นเพียงอีกทางเลือกหนึ่งที่คุณไม่ควรทำหากไม่มีเอกสารประกอบและขั้นตอนการทดสอบการถดถอยอย่างเข้มงวด

นอกจากนี้ Service Pack 1 จะออกยาวของการสนับสนุนที่คุณควรจะได้รับในService Pack 3 + MS15-058


3

ตัวแปรตารางและตาราง temp ได้รับการจัดการแตกต่างกันไปในหลายวิธี มีคำตอบที่ยอดเยี่ยมที่นี่พร้อมข้อมูลเฉพาะมากมายเกี่ยวกับสถานที่ที่แตกต่าง

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

คุณอาจจะดีกว่าการทิ้งตัวแปรตารางลงในตารางชั่วคราวในช่วงระยะเวลาของกระบวนงานที่เก็บไว้

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