2010-05-13 12 views
12

मैं निम्न क्वेरीMySQL: कैसे सूचकांक एक "या" खंड

SELECT COUNT(*) 
FROM table 
WHERE field1='value' AND (field2 >= 1000 OR field3 >= 2000) 

वहाँ फ़ील्ड 1 के ऊपर एक सूचकांक है और एक अन्य field2 & फ़ील्ड 3 से अधिक की संयुक्त क्रियान्वित कर रहा हूँ करने के लिए।

मुझे लगता है कि MySQL हमेशा फील्ड 1 इंडेक्स का चयन करता है और फिर अन्य दो फ़ील्ड का उपयोग करके जुड़ जाता है जो काफी खराब है क्योंकि इसे 146.000 पंक्तियों में शामिल होने की आवश्यकता है।

इसे कैसे सुधारें इस पर सुझाव? धन्यवाद

मैं Mysql पर इस देखा है प्रस्तावित

समाधान में आधारित (प्रस्तावित समाधान की कोशिश के बाद संपादित करें) जब इस के साथ खेल रहा है।

SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1 
UNION SELECT * FROM table WHERE columnB = value2) AS unionTable; 

की तुलना में बहुत धीमी है निष्पादित करें:

SELECT COUNT(*) 
FROM table 
WHERE (columnA = value1 AND columnB = value2) 
     OR (columnA = value1 AND columnC = value3) 

दो कंपोज़िट सूचकांक होने:

index1 (columnA,columnB) 
index2 (columnA,columnC) 

काफी दिलचस्प है कि Mysql पूछ "समझाने" करने के लिए क्वेरी यह हमेशा index1 पर ले रहा है दोनों मामलों और सूचकांक 2 का उपयोग नहीं किया जाता है। क्वेरी के लिए

index1 (columnB,columnA) 
index2 (columnC,columnA) 

और::

SELECT COUNT(*) 
FROM table 
WHERE (columnB = value2 AND columnA = value1) 
     OR (columnC = value3 AND columnA = value1) 

तो यह सबसे तेज़ तरीका मैंने पाया Mysql काम करता है

अगर मैं करने के लिए अनुक्रमित बदल जाते हैं।

उत्तर

17

OR भविष्यवाणियों को तोड़ने का सामान्य तरीका UNION है।

ध्यान दें कि आपका उदाहरण आपकी अनुक्रमणिका के साथ ठीक से फिट नहीं है। भले ही आपने भविष्यवाणी से field1 छोड़ा हो, तो आपके पास field2 >= 1000 OR field3 >= 2000 होगा, जो एक अनुक्रमणिका का उपयोग नहीं कर सकता है। यदि आपके पास (field1, field2) और (field1,field3) या field2 या field3 अलग से इंडेक्स थे, तो आपको एक उचित तेज़ क्वेरी मिल जाएगी।

SELECT COUNT(*) FROM 
(SELECT * FROM table WHERE field1 = 'value' AND field2 >= 1000 
UNION 
SELECT * FROM table WHERE field1 = 'value' AND field3 >= 2000) T 

नोट आप व्युत्पन्न मेज, जिसके कारण सबक्वेरी T के रूप में एलियास किया गया के लिए एक उपनाम प्रदान करने के लिए है।

एक असली दुनिया का उदाहरण। कॉलम और टेबल नामों को अनामित किया गया है!

mysql> SELECT COUNT(*) FROM table; 
+----------+ 
| COUNT(*) | 
+----------+ 
| 3059139 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> SELECT COUNT(*) FROM table WHERE columnA = value1; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  1068 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> SELECT COUNT(*) FROM table WHERE columnB = value2; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  947 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> SELECT COUNT(*) FROM table WHERE columnA = value1 OR columnB = value2; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  1616 | 
+----------+ 
1 row in set (9.92 sec) 

mysql> SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1 
UNION SELECT * FROM table WHERE columnB = value2) T; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  1616 | 
+----------+ 
1 row in set (0.17 sec) 

mysql> SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1 
UNION ALL SELECT * FROM table WHERE columnB = value2) T; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  2015 | 
+----------+ 
1 row in set (0.12 sec) 
+0

आपको एक बग है: आप तत्वों है कि दोनों मानदंडों को पूरा गिनती कर रहे हैं (जहां 'field2> = 1000' * और *' फ़ील्ड 3> = 2000') दो बार। (संकेत: एक अस्थायी तालिका का उपयोग करें;)) – soulmerge

+6

यूनियन डिफ़ॉल्ट रूप से यूनियन डिस्टिंट है। यूनियन निर्माण के हिस्से के रूप में डुप्लिकेट पंक्तियां हटा दी जाती हैं। यदि कोई वास्तव में उन्हें दो बार गिनना है, तो कोई 'यूनियन ऑल' का उपयोग करेगा। क्या आपने अपनी खुद की कुछ समान तालिका पर सुझाए गए कथन का भी प्रयास किया था? –

5

मैं यहाँ नया हूँ, इसलिए मैं अन्य लोगों की पोस्ट पर टिप्पणी नहीं कर सकता, लेकिन इस डेविड एम और soulmerge द्वारा पदों से संबंधित है।

अस्थायी तालिका आवश्यक नहीं है। यूनियन डेविड एम ने दोहराया नहीं है, क्योंकि यूनियन का मतलब एक अलग है (यानी यदि संघ की एक आधे हिस्से में एक पंक्ति मौजूद है, तो इसे दूसरे में अनदेखा करें)। यदि आप यूनियन ऑल का इस्तेमाल करते हैं, तो आपको दो रिकॉर्ड मिलेंगे।

यूनियन के लिए डिफ़ॉल्ट व्यवहार यह है कि परिणाम से डुप्लिकेट पंक्तियां हटा दी जाती हैं।वैकल्पिक DISTINCT कीवर्ड के डिफ़ॉल्ट के अलावा कोई प्रभाव नहीं पड़ता है क्योंकि यह डुप्लिकेट-पंक्ति हटाने को भी निर्दिष्ट करता है। वैकल्पिक सभी कीवर्ड के साथ, डुप्लिकेट-पंक्ति निष्कासन नहीं होता है और परिणाम में सभी चयन पंक्तियों से सभी मिलान पंक्तियां शामिल होती हैं।

http://dev.mysql.com/doc/refman/5.0/en/union.html

संबंधित मुद्दे