एक उपकेंद्र पंक्ति अनुमान को 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;

डीबी फ़िडल लिंक

जवाबों:


22

यह कार्डिनैलिटी अनुमान (CE) सरफेस जारी करता है जब:

  1. ज्वाइन एक बाहरी जुड़ाव है जिसमें पास-थ्रू विधेय होता है
  2. पास-थ्रू विधेय की चयनात्मकता ठीक 1 होने का अनुमान है ।

नोट: चयनात्मकता निर्धारित करने के लिए उपयोग किया जाने वाला विशेष कैलकुलेटर महत्वपूर्ण नहीं है।


विवरण

CE बाहरी योग की चयनात्मकता की गणना निम्न योग के रूप में करता है:

  • भीतरी में शामिल होने के एक ही विधेय के साथ चयनात्मकता
  • विरोधी में शामिल होने के एक ही विधेय के साथ चयनात्मकता

एक बाहरी और आंतरिक जुड़ने के बीच का एकमात्र अंतर यह है कि एक बाहरी जुड़ाव भी पंक्तियों को लौटाता है जो सम्मिलित विधेय पर मेल नहीं खाते हैं। विरोधी जुड़ाव बिल्कुल यही अंतर प्रदान करता है। आंतरिक और विरोधी जुड़ाव के लिए कार्डिनैलिटी का अनुमान बाहरी जुड़ाव से सीधे आसान है।

चयन चयनात्मकता अनुमान प्रक्रिया बहुत सीधी है:

  • सबसे पहले, पास-थ्रू विधेय की चयनात्मकता का मूल्यांकन किया जाता है। SPT
    • यह परिस्थितियों के लिए जो भी कैलकुलेटर उपयुक्त है, का उपयोग करके किया जाता है।
    • किसी भी नकारात्‍मक IsFalseOrNullघटक सहित संपूर्ण चीज़ पूरी तरह से समर्पित है।
  • भीतरी जुड़ाव चयनात्मकता: = 1 - SPT
  • विरोधी शामिल चयनात्मकता: = SPT

एंटी जॉइन उन पंक्तियों का प्रतिनिधित्व करता है जो जुड़ने के दौरान 'गुजरेंगे'। आंतरिक जुड़ाव उन पंक्तियों का प्रतिनिधित्व करता है जो 'से होकर नहीं गुजरेंगे'। ध्यान दें कि 'पास से गुज़रने' का मतलब है कि पंक्तियाँ जो अंदर से बिना भाग के जुड़ती हैं। जोर देने के लिए: सभी पंक्तियों को शामिल होने से वापस कर दिया जाएगा, भेद उन पंक्तियों के बीच है जो उभरने से पहले जुड़ने के आंतरिक पक्ष को चलाते हैं, और जो नहीं करते हैं।

जाहिर है, जोड़ने के लिए हमेशा अर्थ सभी पंक्तियों में शामिल होने के द्वारा दिया जाता है की उम्मीद के रूप में 1 की कुल चयनात्मकता देना चाहिए,।1 - SPTSPT

वास्तव में, उपरोक्त गणना 1 को छोड़कर सभी मूल्यों के लिए ठीक उसी तरह काम करती है ।SPT

जब = 1, दोनों आंतरिक जुड़ाव और विरोधी जुड़ाव चयनात्मकता शून्य होने का अनुमान लगाया जाता है, जिसके परिणामस्वरूप एक पंक्ति का एक कार्डिनैलिटी अनुमान (संपूर्ण के रूप में शामिल होने के लिए) होता है। जहां तक ​​मैं बता सकता हूं, यह अनजाने में है, और इसे बग के रूप में रिपोर्ट किया जाना चाहिए।SPT


एक संबंधित मुद्दा

यह बग एक अलग सीई सीमा के कारण प्रकट होने की संभावना से अधिक हो सकता है। यह तब उत्पन्न होता है जब CASEअभिव्यक्ति एक EXISTSखंड (जैसा कि आम है) का उपयोग करती है। उदाहरण के लिए प्रश्न से निम्नलिखित संशोधित क्वेरी अप्रत्याशित कार्डिनैलिटी अनुमान का सामना नहीं करती है :

-- 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खंड की सामग्री की परवाह किए बिना ।


महत्वपूर्ण पृष्ठभूमि की जानकारी के लिए, क्रेग फ्रीडमैन द्वारा एक्सप्रेशन्स इन CASEएक्सप्रेशंस देखें ।


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;

इस क्वेरी में 1000 पंक्ति अंतिम अनुमान है:

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);

बहुत अंत में कार्डिनैलिटी का अनुमान 1 पंक्ति पर चला जाता है, फिर पास-थ्रू सेलेक्टिविटी = 1. के बाद कार्डिनैलिटी का अनुमान 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);

डिबग आउटपुट में कभी भी एक चरण नहीं होता है जिसमें पास-थ्रू की चयनात्मकता होती है। कार्डिनैलिटी का अनुमान 1000 पंक्तियों पर रहता है।

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. पास-थ्रू चयनात्मकता = 1. दूसरे शब्दों में, CASEसभी पंक्तियों के लिए गलत में से एक भाव का मूल्यांकन किया जाना अपेक्षित है। इससे कोई फर्क नहीं पड़ता कि पहली CASEअभिव्यक्ति सभी पंक्तियों के लिए सही का मूल्यांकन करती है।

  3. इसमें बाहरी जुड़ाव है 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

इस मुद्दे के लिए एक कनेक्ट आइटम प्रस्तुत किया गया था (कुछ विवरण जो पॉल व्हाइट ने अपने उत्तर में दिए हैं)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.