เหตุใดแบบสอบถามย่อยจึงลดการประมาณแถวเป็น 1


26

พิจารณาแบบสอบถามที่ประดิษฐ์ แต่เรียบง่ายต่อไปนี้:

SELECT 
  ID
, CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM X_OTHER_TABLE) 
    ELSE (SELECT TOP 1 ID FROM X_OTHER_TABLE_2) 
  END AS ID2
FROM X_HEAP;

ฉันคาดว่าการประมาณการแถวสุดท้ายสำหรับเคียวรีนี้จะเท่ากับจำนวนแถวในX_HEAPตาราง สิ่งที่ฉันทำในแบบสอบถามย่อยไม่ควรสำคัญกับการประมาณแถวเพราะมันไม่สามารถกรองแถวใด ๆ ออกได้ อย่างไรก็ตามใน SQL Server 2016 ฉันเห็นการประมาณแถวลดลงเป็น 1 เนื่องจากแบบสอบถามย่อย:

ข้อความค้นหาไม่ดี

ทำไมสิ่งนี้ถึงเกิดขึ้น ฉันจะทำอะไรได้บ้าง

มันง่ายมากที่จะทำซ้ำปัญหานี้ด้วยไวยากรณ์ที่ถูกต้อง นี่คือคำจำกัดความของตารางหนึ่งชุดที่จะทำ:

CREATE TABLE dbo.X_HEAP (ID INT NOT NULL)
CREATE TABLE dbo.X_OTHER_TABLE (ID INT NOT NULL);
CREATE TABLE dbo.X_OTHER_TABLE_2 (ID INT NOT NULL);

INSERT INTO dbo.X_HEAP WITH (TABLOCK)
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values;

CREATE STATISTICS X_HEAP__ID ON X_HEAP (ID) WITH FULLSCAN;

DB ซอลิงค์

คำตอบ:


22

ปัญหาการประมาณ cardinality (CE) นี้เกิดขึ้นเมื่อ:

  1. เข้าร่วมเป็นด้านนอกเข้าร่วมกับการส่งผ่านคำกริยา
  2. หัวกะทิของกริยาส่งผ่านคาดว่าจะตรง 1

หมายเหตุ: เครื่องคิดเลขเฉพาะที่ใช้เพื่อพิจารณาการเลือกไม่สำคัญ


รายละเอียด

CE คำนวณการเลือกของการรวมภายนอกเป็นผลรวมของ:

  • ภายในเข้าร่วมการคัดสรรด้วยกริยาเดียวกัน
  • การเลือกเข้าร่วมการต่อต้านที่มีภาคแสดงเดียวกัน

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

กระบวนการประมาณค่าหัวกะทิเข้าร่วมนั้นตรงไปตรงมามาก:

  • ขั้นแรกให้เลือกการประเมินของภาคการส่งผ่านที่มีการประเมิน SPT
    • สิ่งนี้ทำโดยใช้เครื่องคิดเลขที่เหมาะสมกับสถานการณ์
    • เพรดิเคตเป็นสิ่งทั้งหมดรวมถึงIsFalseOrNullองค์ประกอบใด ๆ ที่เป็นลบ
  • การเลือกเข้าร่วมภายใน: = 1 - SPT
  • ต่อต้านการเลือกเข้าร่วม: = SPT

การเข้าร่วมต่อต้านหมายถึงแถวที่จะ 'ผ่าน' การเข้าร่วม การรวมภายในแสดงถึงแถวที่จะไม่ 'ผ่าน' โปรดทราบว่า 'ผ่าน' หมายถึงแถวที่ไหลผ่านการเข้าร่วมโดยไม่ต้องวิ่งด้านในเลย ในการเน้น: แถวทั้งหมดจะถูกส่งกลับโดยการเข้าร่วมความแตกต่างคือระหว่างแถวที่รันด้านในของการเข้าร่วมก่อนที่จะปรากฏขึ้นและแถวที่ไม่ปรากฏ

เห็นได้ชัดว่าการเพิ่มลงไปควรให้ค่าการเลือกโดยรวมเท่ากับ 1 ซึ่งหมายความว่าทุกแถวจะถูกส่งกลับโดยการเข้าร่วมตามที่คาดไว้1 - SPTSPT

อันที่จริงการคำนวณข้างต้นทำงานตรงตามที่อธิบายไว้สำหรับค่าทั้งหมดยกเว้น 1SPT

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


ปัญหาที่เกี่ยวข้อง

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

-- This is fine
SELECT 
    CASE
        WHEN XH.ID = 1
        THEN (SELECT TOP (1) XOT.ID FROM dbo.X_OTHER_TABLE AS XOT) 
    END
FROM dbo.X_HEAP AS XH;

การแนะนำเรื่องเล็กน้อยEXISTSทำให้เกิดปัญหากับพื้นผิว:

-- This is not fine
SELECT 
    CASE
        WHEN EXISTS (SELECT 1 WHERE XH.ID = 1)
        THEN (SELECT TOP (1) XOT.ID FROM dbo.X_OTHER_TABLE AS XOT) 
    END
FROM dbo.X_HEAP AS XH;

การใช้EXISTSแนะนำการเข้าร่วมกึ่ง (เน้น) กับแผนปฏิบัติการ:

เข้าร่วมกึ่งแผน

การประมาณสำหรับการรวมกึ่งทำได้ดี ปัญหาคือว่า CE ถือว่าคอลัมน์โพรบที่เกี่ยวข้องเป็นการฉายอย่างง่ายโดยมีค่าการเลือกคงที่ 1:

Semijoin with probe column treated as a Project.

Selectivity of probe column = 1

สิ่งนี้จะเป็นไปตามเงื่อนไขอย่างใดอย่างหนึ่งที่จำเป็นสำหรับปัญหา CE นี้โดยชัดแจ้งโดยไม่คำนึงถึงเนื้อหาของEXISTSข้อ


สำหรับข้อมูลพื้นฐานที่สำคัญให้ดูแบบสอบถามย่อยในCASEExpressionsโดย Craig Freedman


22

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

จากการทดลองและข้อผิดพลาดเราสามารถค้นหาคำถามที่คล้ายกันซึ่งปัญหาไม่ปรากฏขึ้น:

SELECT 
  ID
, CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    ELSE (SELECT -1) 
  END AS ID2
FROM dbo.X_HEAP;

SELECT 
  ID
, CASE
    WHEN ID < 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    WHEN ID >= 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
  END AS ID2
FROM dbo.X_HEAP;

นอกจากนี้เรายังสามารถค้นหาข้อความค้นหาเพิ่มเติมที่มีปัญหาปรากฏขึ้น:

SELECT 
  ID
, CASE
    WHEN ID < 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    WHEN ID >= 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
    ELSE (SELECT TOP 1 ID FROM X_OTHER_TABLE) 
  END AS ID2
FROM dbo.X_HEAP;

SELECT 
  ID
, CASE
    WHEN ID = 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    ELSE (SELECT -1) 
  END AS ID2
FROM dbo.X_HEAP;

SELECT 
  ID
, CASE
    WHEN ID = 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    ELSE (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
  END AS ID2
FROM dbo.X_HEAP;

ดูเหมือนจะมีรูปแบบ: หากมีการแสดงออกภายในCASEที่ไม่คาดว่าจะได้รับการดำเนินการและการแสดงออกผลเป็นแบบสอบถามย่อยกับตารางจากนั้นประมาณการแถวที่อยู่ที่ 1 หลังจากการแสดงออก

ถ้าฉันเขียนแบบสอบถามกับตารางที่มีดัชนีคลัสเตอร์กฎจะเปลี่ยนไปบ้าง เราสามารถใช้ข้อมูลเดียวกัน:

CREATE TABLE dbo.X_CI (ID INT NOT NULL, PRIMARY KEY (ID))

INSERT INTO dbo.X_CI WITH (TABLOCK)
SELECT * FROM dbo.X_HEAP;

UPDATE STATISTICS X_CI WITH FULLSCAN;

แบบสอบถามนี้มีการประมาณการขั้นสุดท้าย 1,000 แถว:

SELECT 
  ID
, CASE
    WHEN ID = 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
    ELSE (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
  END
FROM dbo.X_CI;

แต่แบบสอบถามนี้มีการประมาณการขั้นสุดท้าย 1 แถว:

SELECT 
  ID
, CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    ELSE (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
  END
FROM dbo.X_CI;

หากต้องการขุดเพิ่มเติมนี้เราสามารถใช้การตั้งค่าสถานะการสืบค้นกลับที่ไม่มีเอกสาร2363เพื่อรับข้อมูลเกี่ยวกับวิธีที่เครื่องมือเพิ่มประสิทธิภาพการสืบค้นทำการคำนวณการเลือก ผมพบว่ามันเป็นประโยชน์ที่จะจับคู่สถานะการติดตามว่ามีไม่มีเอกสารร่องรอยธง 8606 TF 2363 ดูเหมือนจะให้การคำนวณแบบเลือกสำหรับทั้งต้นไม้ที่ง่ายขึ้นและต้นไม้หลังจากการทำให้เป็นมาตรฐานของโครงการ การเปิดใช้งานค่าสถานะการสืบค้นกลับทั้งคู่ทำให้ชัดเจนว่าการคำนวณใดที่นำไปใช้กับต้นไม้

ลองทำกับแบบสอบถามต้นฉบับที่โพสต์ไว้ในคำถาม:

SELECT 
  ID
, CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM X_OTHER_TABLE) 
    ELSE (SELECT TOP 1 ID FROM X_OTHER_TABLE_2) 
  END AS ID2
FROM X_HEAP
OPTION (QUERYTRACEON 3604, QUERYTRACEON 2363, QUERYTRACEON 8606);

นี่เป็นส่วนหนึ่งของผลลัพธ์ที่ฉันคิดว่าเกี่ยวข้องกับความคิดเห็น:

Plan for computation:

  CSelCalcColumnInInterval -- this is the type of calculator used

      Column: QCOL: [SE_DB].[dbo].[X_HEAP].ID -- this is the column used for the calculation

Pass-through selectivity: 0 -- all rows are expected to have a true value for the case expression

Stats collection generated: 

  CStCollOuterJoin(ID=8, CARD=1000 x_jtLeftOuter) -- the row estimate after the join will still be 1000

      CStCollBaseTable(ID=1, CARD=1000 TBL: X_HEAP)

      CStCollBaseTable(ID=2, CARD=1 TBL: X_OTHER_TABLE)

...

Plan for computation:

  CSelCalcColumnInInterval

      Column: QCOL: [SE_DB].[dbo].[X_HEAP].ID

Pass-through selectivity: 1 -- no rows are expected to have a true value for the case expression

Stats collection generated: 

  CStCollOuterJoin(ID=9, CARD=1 x_jtLeftOuter) -- the row estimate after the join will still be 1

      CStCollOuterJoin(ID=8, CARD=1000 x_jtLeftOuter) -- here is the row estimate after the previous join

          CStCollBaseTable(ID=1, CARD=1000 TBL: X_HEAP)

          CStCollBaseTable(ID=2, CARD=1 TBL: X_OTHER_TABLE)

      CStCollBaseTable(ID=3, CARD=1 TBL: X_OTHER_TABLE_2)

ทีนี้ลองหาคำค้นหาที่คล้ายกันที่ไม่มีปัญหา ฉันจะใช้อันนี้:

SELECT 
  ID
, CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    ELSE (SELECT -1) 
  END AS ID2
FROM dbo.X_HEAP
OPTION (QUERYTRACEON 3604, QUERYTRACEON 2363, QUERYTRACEON 8606);

ดีบักเอาต์พุตที่ท้ายสุด:

Plan for computation:

  CSelCalcColumnInInterval

      Column: QCOL: [SE_DB].[dbo].[X_HEAP].ID

Pass-through selectivity: 1

Stats collection generated: 

  CStCollOuterJoin(ID=9, CARD=1000 x_jtLeftOuter)

      CStCollOuterJoin(ID=8, CARD=1000 x_jtLeftOuter)

          CStCollBaseTable(ID=1, CARD=1000 TBL: dbo.X_HEAP)

          CStCollBaseTable(ID=2, CARD=1 TBL: dbo.X_OTHER_TABLE)

      CStCollConstTable(ID=4, CARD=1) -- this is different than before because we select a constant instead of from a table

ลองทำเคียวรีอื่นที่มีการประมาณแถวที่ไม่ดีอยู่:

SELECT 
  ID
, CASE
    WHEN ID < 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    WHEN ID >= 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
    ELSE (SELECT TOP 1 ID FROM X_OTHER_TABLE) 
  END AS ID2
FROM dbo.X_HEAP
OPTION (QUERYTRACEON 3604, QUERYTRACEON 2363, QUERYTRACEON 8606);

ในตอนท้ายสุดการประมาณค่า cardinality จะลดลงเหลือ 1 แถวอีกครั้งหลังจากการเลือกแบบพาส - ทรู = 1 การประมาณค่าแบบ cardinality นั้นจะยังคงอยู่หลังจากค่าการเลือกที่ 0.501 และ 0.499

Plan for computation:

 CSelCalcColumnInInterval

      Column: QCOL: [SE_DB].[dbo].[X_HEAP].ID

Pass-through selectivity: 0.501

...

Plan for computation:

  CSelCalcColumnInInterval

      Column: QCOL: [SE_DB].[dbo].[X_HEAP].ID

Pass-through selectivity: 0.499

...

Plan for computation:

  CSelCalcColumnInInterval

      Column: QCOL: [SE_DB].[dbo].[X_HEAP].ID

Pass-through selectivity: 1

Stats collection generated: 

  CStCollOuterJoin(ID=12, CARD=1 x_jtLeftOuter) -- this is associated with the ELSE expression

      CStCollOuterJoin(ID=11, CARD=1000 x_jtLeftOuter)

          CStCollOuterJoin(ID=10, CARD=1000 x_jtLeftOuter)

              CStCollBaseTable(ID=1, CARD=1000 TBL: dbo.X_HEAP)

              CStCollBaseTable(ID=2, CARD=1 TBL: dbo.X_OTHER_TABLE)

          CStCollBaseTable(ID=3, CARD=1 TBL: dbo.X_OTHER_TABLE_2)

      CStCollBaseTable(ID=4, CARD=1 TBL: X_OTHER_TABLE)

ลองสลับไปยังอีกแบบสอบถามที่คล้ายกันที่ไม่มีปัญหา ฉันจะใช้อันนี้:

SELECT 
  ID
, CASE
    WHEN ID < 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    WHEN ID >= 500 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
  END AS ID2
FROM dbo.X_HEAP
OPTION (QUERYTRACEON 3604, QUERYTRACEON 2363, QUERYTRACEON 8606);

ในผลลัพธ์การดีบักไม่เคยมีขั้นตอนใดที่มีการเลือกผ่านแบบ 1 การประมาณความน่าจะอยู่ที่ 1,000 แถว

Plan for computation:

  CSelCalcColumnInInterval

      Column: QCOL: [SE_DB].[dbo].[X_HEAP].ID

Pass-through selectivity: 0.499

Stats collection generated: 

  CStCollOuterJoin(ID=9, CARD=1000 x_jtLeftOuter)

      CStCollOuterJoin(ID=8, CARD=1000 x_jtLeftOuter)

          CStCollBaseTable(ID=1, CARD=1000 TBL: dbo.X_HEAP)

          CStCollBaseTable(ID=2, CARD=1 TBL: dbo.X_OTHER_TABLE)

      CStCollBaseTable(ID=3, CARD=1 TBL: dbo.X_OTHER_TABLE_2)

End selectivity computation

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

SELECT 
  ID
, CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
    ELSE (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
  END
FROM dbo.X_CI
OPTION (QUERYTRACEON 3604, QUERYTRACEON 2363, QUERYTRACEON 8606);

จุดสิ้นสุดของเอาต์พุตดีบักคล้ายกับสิ่งที่เราได้เห็นแล้ว:

Plan for computation:

  CSelCalcColumnInInterval

      Column: QCOL: [SE_DB].[dbo].[X_CI].ID

Pass-through selectivity: 1

Stats collection generated: 

  CStCollOuterJoin(ID=9, CARD=1 x_jtLeftOuter)

      CStCollOuterJoin(ID=8, CARD=1000 x_jtLeftOuter)

          CStCollBaseTable(ID=1, CARD=1000 TBL: dbo.X_CI)

          CStCollBaseTable(ID=2, CARD=1 TBL: dbo.X_OTHER_TABLE)

      CStCollBaseTable(ID=3, CARD=1 TBL: dbo.X_OTHER_TABLE_2)

อย่างไรก็ตามเคียวรีกับ CI ที่ไม่มีปัญหามีเอาต์พุตต่างกัน ใช้แบบสอบถามนี้:

SELECT 
  ID
, CASE
    WHEN ID = 0 
    THEN (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE_2) 
    ELSE (SELECT TOP 1 ID FROM dbo.X_OTHER_TABLE) 
  END
FROM dbo.X_CI
OPTION (QUERYTRACEON 3604, QUERYTRACEON 2363, QUERYTRACEON 8606);

ผลลัพธ์ในการใช้เครื่องคิดเลขที่แตกต่างกัน CSelCalcColumnInIntervalไม่ปรากฏอีกต่อไป:

Plan for computation:

  CSelCalcFixedFilter (0.559)

Pass-through selectivity: 0.559

Stats collection generated: 

  CStCollOuterJoin(ID=8, CARD=1000 x_jtLeftOuter)

      CStCollBaseTable(ID=1, CARD=1000 TBL: dbo.X_CI)

      CStCollBaseTable(ID=2, CARD=1 TBL: dbo.X_OTHER_TABLE_2)

...

Plan for computation:

  CSelCalcUniqueKeyFilter

Pass-through selectivity: 0.001

Stats collection generated: 

  CStCollOuterJoin(ID=9, CARD=1000 x_jtLeftOuter)

      CStCollOuterJoin(ID=8, CARD=1000 x_jtLeftOuter)

          CStCollBaseTable(ID=1, CARD=1000 TBL: dbo.X_CI)

          CStCollBaseTable(ID=2, CARD=1 TBL: dbo.X_OTHER_TABLE_2)

      CStCollBaseTable(ID=3, CARD=1 TBL: dbo.X_OTHER_TABLE)

โดยสรุปเราดูเหมือนจะได้รับการประมาณการแถวที่ไม่ดีหลังจากแบบสอบถามย่อยภายใต้เงื่อนไขดังต่อไปนี้:

  1. CSelCalcColumnInIntervalเครื่องคิดเลขหัวกะทิถูกนำมาใช้ ฉันไม่รู้ว่ามันถูกใช้ไปเมื่อไหร่ แต่ดูเหมือนว่าจะปรากฏบ่อยขึ้นเมื่อตารางฐานเป็นกอง

  2. Pass-through selectivity = 1 กล่าวอีกนัยหนึ่งCASEคาดว่าจะมีการแสดงออกอย่างใดอย่างหนึ่งเป็นเท็จสำหรับทุกแถว มันไม่สำคัญว่าCASEนิพจน์แรกประเมินว่าเป็นจริงสำหรับทุกแถว

  3. มีการเข้าร่วม outer CStCollBaseTableไป กล่าวอีกนัยหนึ่งการCASEแสดงออกของผลลัพธ์เป็นแบบสอบถามย่อยเทียบกับตาราง ค่าคงที่จะไม่ทำงาน

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

ฉันสามารถหาวิธีแก้ไขสองวิธี ฉันไม่สามารถทำซ้ำปัญหาเมื่อใช้APPLYแทนแบบสอบถามย่อย การส่งออกของร่องรอยธง 2363 APPLYแตกต่างอย่างมากกับ ต่อไปนี้เป็นวิธีหนึ่งในการเขียนแบบสอบถามต้นฉบับในคำถาม:

SELECT 
  h.ID
, a.ID2
FROM X_HEAP h
OUTER APPLY
(
SELECT CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM X_OTHER_TABLE) 
    ELSE (SELECT TOP 1 ID FROM X_OTHER_TABLE_2) 
  END
) a(ID2);

แบบสอบถามที่ดี 1

CE ดั้งเดิมปรากฏขึ้นเพื่อหลีกเลี่ยงปัญหานี้เช่นกัน

SELECT 
  ID
, CASE
    WHEN ID <> 0 
    THEN (SELECT TOP 1 ID FROM X_OTHER_TABLE) 
    ELSE (SELECT TOP 1 ID FROM X_OTHER_TABLE_2) 
  END AS ID2
FROM X_HEAP
OPTION (USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'));

แบบสอบถามที่ดี 2

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

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