2012-10-03 17 views
5

से एसक्यूएल सबक्वायरीज़ मैं समझता हूं कि गलत तरीके से उपयोग किए जाने पर प्रदर्शन के लिए subqueries कुख्यात रूप से खराब हैं। मेरे पास एक बहुत विशिष्ट परिदृश्य है जहां उपयोगकर्ता को तालिका से रिकॉर्ड्स के फ़िल्टर किए गए सेट को पुनर्प्राप्त करने की आवश्यकता होती है। विभिन्न प्रकार के फ़िल्टर उपलब्ध होंगे और उन्हें संरचना का समर्थन करना होगा। इसके अलावा, डेवलपर्स के एक समूह द्वारा नियमित रूप से नए फ़िल्टर बनाए जाएंगे।क्लॉज

मुझे पैरामीटर की कुल संख्या के साथ एक बढ़ती, एकात्मक एसक्यूएल क्वेरी का विचार पसंद नहीं है। मुझे समान चयन कथन के साथ स्वायत्त एसक्यूएल प्रश्नों के समूह का विचार पसंद नहीं है और अलग-अलग कहां खंड हैं। मुझे एक गतिशील एसक्यूएल क्वेरी का विचार पसंद है, लेकिन मुझे यकीन नहीं है कि मुझे किस प्रकार की संरचना का उपयोग करना चाहिए। मैं 4 बुनियादी विकल्प के बारे में सोच सकते हैं: (यदि वहाँ अधिक है कि मैं याद कर रहा हूँ कर रहे हैं, तो कृपया उन्हें सुझाव देने में संकोच नहीं करते)

  1. "आंतरिक शामिल हों": इनर के माध्यम से फिल्टर जुटना परिणामों को फ़िल्टर करने मिलती है।
  2. "उपरोक्त से": FROM कथन में सबक्वायरीज़ के माध्यम से फ़िल्टर ढेर करें।
  3. "कहां सबक्वायरीज़": WHERE खंड में सबक्वायरीज़ के माध्यम से फ़िल्टर को संगत करें।
  4. "इनर जॉइन सबक्वायरीज़": एक व्यापक हाइब्रिड।

मैं प्रदर्शित करने के लिए (और प्रोफ़ाइल) एक एसक्यूएल बेला बना लिया है उन्हें:

http://sqlfiddle.com/#!3/4e17b/9

नीचे

मैं क्या 'की एक विचार प्रदान करने के लिए बेला से एक अंश है मीटर के बारे में बात:

------------------------------------------------------------------------ 
--THIS IS AN EXCERPT FROM THE SQL FIDDLE -- IT IS NOT MEANT TO COMPILE-- 
------------------------------------------------------------------------ 

-- 
--"INNER JOIN" test 
     SELECT COUNT(*) 
     FROM 
      @TestTable Test0 
      INNER JOIN @TestTable Test1 ON Test1.ID=Test0.ID AND Test1.ID % @i = 0 
      INNER JOIN @TestTable Test2 ON Test2.ID=Test0.ID AND Test2.ID % @j = 0 
      INNER JOIN @TestTable Test3 ON Test3.ID=Test0.ID AND Test3.ID % @k = 0 

-- 
--"FROM subqueries" test 
     SELECT COUNT(*) FROM (
      SELECT * FROM (
        SELECT * FROM (
         SELECT * FROM @TestTable Test3 WHERE Test3.ID % @k = 0 
       ) Test2 WHERE Test2.ID % @j = 0 
      ) Test1 WHERE Test1.ID % @i = 0 
    ) Test0 

-- 
--"WHERE subqueries" test 
     SELECT COUNT(*) 
     FROM @TestTable Test0 
     WHERE 
      Test0.ID IN (SELECT ID FROM @TestTable Test1 WHERE Test1.ID % @i = 0) 
      AND Test0.ID IN (SELECT ID FROM @TestTable Test2 WHERE Test2.ID % @j = 0) 
      AND Test0.ID IN (SELECT ID FROM @TestTable Test3 WHERE Test3.ID % @k = 0) 

-- 
--"INNER JOIN subqueries" test 
    SELECT COUNT(*) 
    FROM 
     TestTable Test0 
     INNER JOIN (SELECT ID FROM TestTable WHERE ID % @i = 0) Test1 ON Test1.ID=Test0.ID 
     INNER JOIN (SELECT ID FROM TestTable WHERE ID % @j = 0) Test2 ON Test2.ID=Test0.ID 
     INNER JOIN (SELECT ID FROM TestTable WHERE ID % @k = 0) Test3 ON Test3.ID=Test0.ID 

-- 
--"EXISTS subqueries" test 
    SELECT COUNT(*) 
    FROM TestTable Test0 
    WHERE 
     EXISTS (SELECT 1 FROM TestTable Test1 WHERE Test1.ID = Test0.ID AND Test1.ID % @i = 0) 
     AND EXISTS (SELECT 1 FROM TestTable Test2 WHERE Test2.ID = Test0.ID AND Test2.ID % @j = 0) 
     AND EXISTS (SELECT 1 FROM TestTable Test3 WHERE Test3.ID = Test0.ID AND Test3.ID % @k = 0) 

रैंकिंग

01 (समय परीक्षण निष्पादित करने के लिए)

एसक्यूएल फिडल:

|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES| 
------------------------------------------------------------------------------------- 
|  5174 |   777 |   7240 |    5478 |   7359 | 

स्थानीय पर्यावरण: (कोई कैश के साथ: हर परीक्षण से पहले समाशोधन बफर)

|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES| 
------------------------------------------------------------------------------------- 
|  3281 |   2851 |   2964 |    3148 |   3071 | 

स्थानीय पर्यावरण: (कैश के साथ: एक पंक्ति में चल प्रश्नों दो बार और रिकॉर्ड 2 रन के समय)

|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES| 
------------------------------------------------------------------------------------- 
|  284 |   50 |   3334 |     278 |    408 | 

प्रत्येक समाधान के साथ लाभ/नुकसान कर रहे हैं। WHERE खंड में subqueries बहुत भयानक प्रदर्शन है। एफरोम क्लॉज में उप-सामानों में बहुत अच्छा प्रदर्शन होता है (वास्तव में वे आमतौर पर सर्वश्रेष्ठ प्रदर्शन करते हैं) (नोट: मुझे विश्वास है कि यह विधि इंडेक्स के लाभों को अस्वीकार करेगी?)। इनर जॉइन के पास बहुत अच्छा प्रदर्शन है, हालांकि इसमें कुछ रोचक स्कोपिंग मुद्दे शामिल हैं क्योंकि सबक्वायरीज़ के विपरीत, इनर जॉइन एक ही संदर्भ में परिचालन करेंगे (तालिका उपनामों के टकराव से बचने के लिए मध्यस्थ प्रणाली होना आवश्यक होगा)।

कुल मिलाकर मुझे लगता है कि सबसे साफ समाधान FROM खंड में subqueries है। फ़िल्टर लिखना और परीक्षण करना आसान होगा (क्योंकि इनर जॉइन के विपरीत उन्हें संदर्भ/आधार क्वेरी के साथ प्रदान करने की आवश्यकता नहीं होगी)।

विचार? क्या यह सबक्वायरी या आपदा होने का इंतजार कर रहा है?

अद्यतन (2012/10/04):

  • अपडेट किया गया एसक्यूएल फिडल एक परीक्षण शामिल करने के लिए विधि
  • जोड़ा प्रदर्शन एसक्यूएल फिडल से परीक्षण और स्थानीय पर्यावरण "मौजूद है" के लिए

उत्तर

0

हैं आप हमेशा आवेदन करने जा रहे हैं "और" आंतरिक शामिल होने का तर्क शायद एक अच्छा दृष्टिकोण है (मैं सामान्यीकरण कर रहा हूं, लेकिन यह आपके टेबल आकार और इंडेक्स आदि सहित कई कारकों से भिन्न होगा)। यदि आप "और" या "या" फ़िल्टरिंग लागू करने में सक्षम होना चाहते हैं तो आपको अन्य समाधानों में से एक का उपयोग करने की आवश्यकता होगी।

इसके अलावा, आप का उपयोग कर प्रदर्शन बाहर का परीक्षण करना चाहिए खंड मौजूद है:

SELECT COUNT(*) 
     FROM @TestTable Test0 
     WHERE 
      EXISTS (SELECT 1 FROM @TestTable Test1 WHERE Test0.ID = Test1.ID AND Test1.ID % @i = 0) 
      EXISTS (SELECT 1 FROM @TestTable Test2 WHERE Test0.ID = Test2.ID AND Test2.ID % @j = 0) 
      EXISTS (SELECT 1 FROM @TestTable Test3 WHERE Test0.ID = Test3.ID AND Test3.ID % @k = 0) 
+0

जोड़ी परीक्षण "मौजूद है" विधि के लिए। यह पैक के पूंछ के अंत के पास है, हालांकि मैं "चयन *" और "चयन 1" के बीच कुछ अंतर देखने के लिए आश्चर्यचकित था (निश्चित रूप से सबसे नियंत्रित परीक्षण नहीं, लेकिन कुछ निश्चित भिन्नता थी)। सामान्य पद्धति विभिन्न तालिकाओं पर लागू की जाएगी, इसलिए आकार और सूचकांक अग्रिम में पूर्वानुमान करना मुश्किल है। मैं मूल रूप से "सबसे दोस्ताना सैंडबॉक्स" ढूंढ रहा हूं। – makerplays