या जोइन क्लॉज में या का उपयोग करते समय अजीब क्वेरी योजना - तालिका में प्रत्येक पंक्ति के लिए लगातार स्कैन


10

मैं यह दिखाने के लिए एक नमूना क्वेरी योजना तैयार करने की कोशिश कर रहा हूं कि दो परिणाम सेटों का उपयोग करना या एक JOIN क्लॉज में उपयोग करने से बेहतर क्यों हो सकता है। मेरे द्वारा लिखी गई एक क्वेरी योजना ने मुझे स्टम्प किया है। मैं StackOverflow डेटाबेस का उपयोग Users.Reputation पर एक गैर-अनुक्रमित सूचकांक के साथ कर रहा हूँ।

क्वेरी योजना छवि क्वेरी है

CREATE NONCLUSTERED INDEX IX_NC_REPUTATION ON dbo.USERS(Reputation)
SELECT DISTINCT Users.Id
FROM dbo.Users
INNER JOIN dbo.Posts  
    ON Users.Id = Posts.OwnerUserId
    OR Users.Id = Posts.LastEditorUserId
WHERE Users.Reputation = 5

क्वेरी प्लान https://www.brentozar.com/pastetheplan/?id=BkpZU1MZE पर है , मेरे लिए क्वेरी अवधि 4:37 मिनट, 26612 पंक्तियाँ वापस आ गईं।

मैंने किसी मौजूदा टेबल से निरंतर-स्कैन की इस शैली को पहले नहीं देखा है - मैं इस बात से अपरिचित हूं कि हर एक पंक्ति के लिए एक निरंतर स्कैन क्यों होता है, जब उपयोगकर्ता द्वारा इनपुट की गई एकल पंक्ति के लिए आमतौर पर एक निरंतर स्कैन का उपयोग किया जाता है उदाहरण के लिए सेलेक्ट गेटेट () चुनें। इसका उपयोग यहाँ क्यों किया जाता है? मैं वास्तव में इस क्वेरी योजना को पढ़ने में कुछ मार्गदर्शन की सराहना करूंगा।

अगर मैं इसे अलग करता हूं या UNION में विभाजित करता हूं, तो यह 12 सेकंड में चलने वाली एक मानक योजना बनाता है जिसमें 26612 पंक्तियां वापस आती हैं।

SELECT Users.Id
FROM dbo.Users
    INNER JOIN dbo.Posts
       ON Users.Id = Posts.OwnerUserId
WHERE Users.Reputation = 5
UNION 
SELECT Users.Id
FROM dbo.Users
    INNER JOIN dbo.Posts
       ON  Users.Id = Posts.LastEditorUserId
WHERE Users.Reputation = 5

मैं इस योजना की व्याख्या इस प्रकार कर रहा हूं:

  • सभी 41782500 पंक्तियों को पोस्ट से प्राप्त करें (पंक्तियों की वास्तविक संख्या पोस्ट पर CI स्कैन से मेल खाती है)
  • पोस्ट में प्रत्येक 41782500 पंक्तियों के लिए:
    • स्केलर का उत्पादन करें:
    • Expr1005: OwnerUserId
    • Expr1006: OwnerUserId
    • Expr1004: स्थिर मूल्य 62
    • Expr1008: LastEditorUserId
    • Expr1009: LastEditorUserId
    • Expr1007: स्थिर मूल्य 62
  • संघात में:
    • Exp1010: यदि Expr1005 (OwnerUserId) शून्य नहीं है, तो उस अन्य का उपयोग करें Expr1008 (LastEditorUserID) का उपयोग करें
    • Expr1011: यदि Expr1006 (OwnerUserId) शून्य नहीं है, तो उसका उपयोग करें, अन्यथा Expr1009 (LastEditorUserId) का उपयोग करें
    • Expr1012: अगर Expr1004 (62) शून्य उपयोग है, तो Expr1007 (62) का उपयोग करें
  • गणना स्केलर में: मुझे नहीं पता कि एक एम्परसेंड क्या करता है।
    • Expr1013: 4 [और?] 62 (Expr1012) = 4 और OwnerUserId IS NULL (NULL = Expr1010) है
    • Expr1014: 4 [और?] 62 (Expr1012)
    • Expr1015: 16 और 62 (Expr1012)
  • द्वारा क्रम में द्वारा:
    • Expr1013 Desc
    • Expr1014 Asc
    • Expr1010 Asc
    • Expr1015 उतर
  • मर्ज इंटरवल में यह Expr1013 और Expr1015 को हटा दिया (ये इनपुट हैं, लेकिन आउटपुट नहीं हैं)
  • नेस्टेड लूप के नीचे इंडेक्स की तलाश में यह शामिल है कि Expr1010 और Expr1011 का उपयोग विधेय की तलाश के रूप में किया जा रहा है, लेकिन मुझे यह समझ में नहीं आता है कि जब यह नेस्टेड लूप IX_NC_REPREATION से एक्सप्रि 1 और Expr1011 युक्त सबट्री से जुड़ता नहीं है, तो इन तक इसकी पहुंच कैसे होती है। ।
  • नेस्टेड लूप्स केवल उन यूजर्स से जुड़ते हैं, जिनके पास पहले के सबट्री में मैच होता है। विधेय पुशडेक के कारण, IX_NC_REPUTATION पर अनुक्रमणिका की तलाश से लौटी सभी पंक्तियाँ वापस आ जाती हैं।
  • अंतिम नेस्टेड लूप शामिल होते हैं: प्रत्येक पोस्ट रिकॉर्ड के लिए, Users.d आउटपुट करते हैं, जहां नीचे डेटासेट में एक मैच पाया जाता है।

क्या आपने EXISTS उपश्रेणी या उपश्रेणियों के साथ प्रयास किया? SELECT Users.Id FROM dbo.Users WHERE Users.Reputation = 5 AND ( EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id = Posts.OwnerUserId) OR EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id = Posts.LastEditorUserId) ) ;
ypercube y

एक SELECT Users.Id FROM dbo.Users WHERE Users.Reputation = 5 AND EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id IN (Posts.OwnerUserId, Posts.LastEditorUserId) ) ;
उपश्रेणी

जवाबों:


10

यह योजना उसी के समान है जिसे मैं यहां अधिक विस्तार से बताता हूं ।

Postsतालिका स्कैन किया जाता है।

प्रत्येक पंक्ति के लिए यह a OwnerUserIdऔर निकालता है LastEditorUserId। यह UNPIVOTकाम करने के तरीके के समान है । आप प्रत्येक इनपुट पंक्ति के लिए दो आउटपुट पंक्तियों को बनाने के लिए नीचे दिए गए प्लान में एक सिंगल निरंतर स्कैन ऑपरेटर देखते हैं।

SELECT *
FROM dbo.Posts
UNPIVOT (X FOR U IN (OwnerUserId,LastEditorUserId)) Unpvt

इस मामले में यह योजना थोड़ी अधिक जटिल है क्योंकि इसके लिए शब्दार्थ orयह है कि यदि दोनों स्तंभ मान एक ही हैं, तो केवल एक पंक्ति को ही सम्मिलित होने पर Users(दो नहीं) से उत्सर्जित किया जाना चाहिए।

फिर उन्हें मर्ज अंतराल के माध्यम से रखा जाता है ताकि इस घटना में मान समान हों और सीमा नीचे गिर जाए और केवल एक ही खोज को अंजाम दिया जाए Users- अन्यथा इसके खिलाफ दो प्रयास किए जाते हैं।

मूल्य 62एक ध्वज का अर्थ है कि साधक को एक समानता चाहिए।

के बारे में

मुझे समझ में नहीं आता कि जब यह नेस्टेड लूप IX_NC_REPUTATION से एक्सप्रि 1 और Expr1011 युक्त सबट्री से जुड़ता है, तो इन तक इसकी पहुंच कैसे होती है

ये पीले हाइलाइटेड कॉन्टेक्नेशन ऑपरेटर में परिभाषित किए गए हैं। यह पीले हाइलाइटेड नेस्टेड छोरों के बाहरी तरफ है। इससे पहले कि यह नेस्टेड छोरों के अंदर पीले हाइलाइट की तलाश से पहले चलता है।

यहाँ छवि विवरण दर्ज करें

एक पुनर्लेखन जो एक समान योजना देता है (हालांकि मर्ज के अंतराल को मर्ज यूनियन द्वारा प्रतिस्थापित किया जाता है) इस मामले में नीचे होता है।

SELECT DISTINCT D2.UserId
FROM   dbo.Posts p
       CROSS APPLY (SELECT Users.Id AS UserId
                    FROM   (SELECT p.OwnerUserId
                            UNION /*collapse duplicate to single row*/
                            SELECT p.LastEditorUserId) D1(UserId)
                           JOIN Users
                             ON Users.Id = D1.UserId) D2
OPTION (FORCE ORDER) 

यहाँ छवि विवरण दर्ज करें

Postsइस क्वेरी के वैरिएबल आपके अनुक्रमित UNION ALLसमाधान की तुलना में अधिक कुशल हो सकते हैं, इस बात पर निर्भर करता है कि तालिका में कौन सा संस्करण उपलब्ध है । (डेटाबेस की प्रतिलिपि मेरे पास इसके लिए कोई उपयोगी सूचकांक नहीं है और प्रस्तावित समाधान दो पूर्ण स्कैन करता है Posts। नीचे यह एक चरण में किया गया है)

WITH Unpivoted AS
(
SELECT UserId
FROM dbo.Posts
UNPIVOT (UserId FOR U IN (OwnerUserId,LastEditorUserId)) Unpivoted
)
SELECT DISTINCT Users.Id
FROM dbo.Users INNER HASH JOIN Unpivoted
       ON  Users.Id = Unpivoted.UserId
WHERE Users.Reputation = 5

यहाँ छवि विवरण दर्ज करें

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