ดัชนีคอลัมน์ที่คำนวณแล้วไม่ได้ใช้


14

ฉันต้องการค้นหาแบบเร็วโดยดูจากว่ามีสองคอลัมน์เท่ากัน ฉันพยายามใช้คอลัมน์ที่คำนวณด้วยดัชนี แต่ SQL Server ดูเหมือนจะไม่ใช้มัน ถ้าฉันใช้คอลัมน์บิตที่มีค่าคงที่กับดัชนีฉันจะได้ดัชนีที่ต้องการ

ดูเหมือนว่ามีคำถามอื่น ๆ เช่นนี้อยู่ที่นั่น แต่ไม่มีใครสนใจว่าทำไมดัชนีจะไม่ถูกใช้

ตารางทดสอบ:

CREATE TABLE dbo.Diffs
    (
    Id int NOT NULL IDENTITY (1, 1),
    DataA int NULL,
    DataB int NULL,
    DiffPersisted  AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0) PERSISTED ,
    DiffComp  AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0),
    DiffStatic bit not null,
    Primary Key (Id)
    )

create index ix_DiffPersisted on Diffs (DiffPersisted)
create index ix_DiffComp on Diffs (DiffComp)
create index ix_DiffStatic on Diffs (DiffStatic)

และการค้นหา:

select Id from Diffs where DiffPersisted = 1
select Id from Diffs where DiffComp = 1
select Id from Diffs where DiffStatic = 1

และแผนการดำเนินการที่เกิดขึ้น: แผนปฏิบัติการ

คำตอบ:


10

ลองกับแทนCOALESCE ISNULLด้วยISNULLSQL Server ดูเหมือนจะไม่สามารถผลักภาคแสดงกับดัชนีที่แคบลงดังนั้นจึงต้องสแกนคลัสเตอร์เพื่อค้นหาข้อมูล

CREATE TABLE dbo.Diffs
    (
    Id int NOT NULL IDENTITY (1, 1),
    DataA int NULL,
    DataB int NULL,
    DiffPersisted  AS COALESCE(convert(bit, case when [DataA] is null 
      and [DataB] is not null then 1 when [DataA] <> [DataB] 
      then 1 else 0 end), 0) PERSISTED ,
    DiffComp  AS COALESCE(convert(bit, case when [DataA] is null 
      and [DataB] is not null then 1 when [DataA] <> [DataB] 
      then 1 else 0 end), 0),
    DiffStatic bit not null,
    Primary Key (Id)
    );

ที่กล่าวว่าหากคุณติดกับคอลัมน์แบบคงที่ดัชนีที่กรองอาจเหมาะสมกว่าและจะมีค่าใช้จ่าย I / O ที่ลดลง (ทั้งหมดขึ้นอยู่กับจำนวนแถวที่ตรงกับเพรดิเคตตัวกรอง) เช่น:

CREATE INDEX ix_DiffStaticFiltered 
  ON dbo.Diffs(DiffStatic)
  WHERE DiffStatic = 1;

ที่น่าสนใจมากคงไม่คิดอย่างนี้ ดูเหมือนว่าคุณสามารถกำจัดCOALESCEจุดนี้ได้แม้ว่า; ฉันเชื่อว่าCASEคำสั่งรับประกันแล้วว่าจะส่งคืน0หรือ1แต่ISNULLมีอยู่เท่านั้นดังนั้น SQL Server จะให้ผลลัพธ์ที่ไม่เป็นโมฆะBITสำหรับคอลัมน์ที่คำนวณ อย่างไรก็ตามCOALESCEจะยังคงให้ผลลัพธ์เป็นคอลัมน์ที่ไม่สามารถใช้ได้ ดังนั้นผลกระทบเดียวของการเปลี่ยนแปลงนี้โดยมีหรือไม่มีCOALESCEคอลัมน์คือคอลัมน์ที่คำนวณในขณะนี้เป็นโมฆะ แต่สามารถค้นหาดัชนีได้
Geoff Patterson

@Geoff ใช่มันเป็นเรื่องจริง แต่ในกรณีนี้เนื่องจากเรารู้จากนิยามคอลัมน์ที่คำนวณแล้ว NULL นั้นไม่ใช่เอาต์พุตที่เป็นไปได้สิ่งนี้สำคัญมากถ้าเราใช้ตารางนี้เป็นแหล่งที่มาของ SELECT INTO
แอรอนเบอร์ทรานด์ด์

นี่คือข้อมูลที่น่าอัศจรรย์ - ขอบคุณ! เป้าหมายสุดท้ายของฉันคือการใช้คอลัมน์ DataA และ DataB เป็น uuids "สกปรก" เพื่ออนุญาตให้อัปเดตแบบอะซิงโครนัสของคอลัมน์ denormalized บนระเบียนดังนั้นไม่ควรมีมากเกินไปเมื่อค่าสถานะ Diff เป็น 1 หากฉันใช้ static จากนั้นฉันก็คิดที่จะเพิ่มทริกเกอร์เพื่อตรวจสอบ uuids ทั้งสองและอัพเดทฟิลด์
David Faivre

นอกจากนี้ในฐานะ @GeoffPatterson ชี้สามารถฉันได้ใช้COALESCE? ทำไมฉันต้องเก็บมันไว้?
David Faivre

@ David COALESCEคุณอาจจะสามารถวาง ฉันพยายามที่จะรักษารูปลักษณ์และเจตนาของรหัสดั้งเดิมของคุณและไม่ได้ทำการทดสอบโดยที่ไม่ใช้มันดังนั้นการทดสอบจะเกิดขึ้นกับคุณ (ฉันไม่สามารถอธิบายได้ว่าทำไมคุณถึงISNULLอยู่ที่นั่นตั้งแต่แรก)
Aaron Bertrand

5

นี่คือข้อ จำกัด ที่เฉพาะเจาะจงของตรรกะการจับคู่คอลัมน์ SQL Server คำนวณเมื่อสุดถูกนำมาใช้และประเภทข้อมูลของคอลัมน์คือISNULLbit

รายงานข้อผิดพลาด

เพื่อหลีกเลี่ยงปัญหาการแก้ไขปัญหาใด ๆ ต่อไปนี้อาจได้รับการว่าจ้าง:

  1. อย่าใช้นอกสุดISNULL(วิธีเดียวที่จะทำให้คอลัมน์ที่คำนวณNOT NULL)
  2. อย่าใช้bitชนิดข้อมูลเป็นชนิดสุดท้ายของคอลัมน์จากการคำนวณ
  3. ทำให้คอลัมน์คำนวณPERSISTEDและช่วยให้สถานะการติดตาม 174

รายละเอียด

หัวใจสำคัญของปัญหาคือไม่มีการตั้งค่าสถานะการสืบค้นกลับ 174 การอ้างอิงคอลัมน์ที่คำนวณทั้งหมดในแบบสอบถาม (ยังคงมีอยู่) จะถูกขยายเข้าไปในคำจำกัดความพื้นฐานเสมอก่อนในการรวบรวมแบบสอบถาม

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

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

นิพจน์คอลัมน์ที่คำนวณแล้วไม่เปลี่ยนแปลงจะจับคู่กลับไปยังคอลัมน์ที่คำนวณดั้งเดิมโดยไม่มีปัญหาในกรณีส่วนใหญ่ มีปรากฏเป็นข้อผิดพลาดเมื่อเฉพาะกับการจับคู่การแสดงออกของชนิดที่มีชั้นนอกสุดbit ISNULLการจับคู่ไม่สำเร็จในกรณีเฉพาะนี้แม้ว่าการตรวจสอบภายในอย่างละเอียดแสดงให้เห็นว่าควรประสบความสำเร็จ

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