इसका कारण OR . के उपयोग में निहित है कहां . में स्थितियां खंड।
उदाहरण के लिए, क्वेरी को फिर से चलाने का प्रयास करें, इस बार केवल id = 5
. के साथ कंडीशन, और प्राप्त करें (EXPLAIN आउटपुट):
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | |
| 1 | PRIMARY | tree | const | PRIMARY,index_both | PRIMARY | 4 | const | 1 | |
| 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
और फिर, इस बार केवल parent_id = @last_id OR parent_id = 5
के साथ शर्त, और प्राप्त करें:
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | |
| 1 | PRIMARY | tree | ALL | index_parent_id | NULL | NULL | NULL | 10 | Using where |
| 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
MySQL एक ही क्वेरी में एकाधिक अनुक्रमणिका को संभालने के साथ बहुत अच्छा नहीं है। AND शर्तों के साथ चीज़ें थोड़ी बेहतर हैं; किसी को index_merge एक इंडेक्स यूनियन की तुलना में ऑप्टिमाइज़ेशन अनुकूलन।
जैसे-जैसे संस्करण आगे बढ़ते हैं, चीजें बेहतर होती जा रही हैं, लेकिन मैंने संस्करण 5.5
. पर आपकी क्वेरी का परीक्षण किया है , जो वर्तमान नवीनतम उत्पादन संस्करण में है, और परिणाम आपके वर्णन के अनुसार हैं।
यह समझाने के लिए कि यह मुश्किल क्यों है, इस पर विचार करें:दो अलग-अलग इंडेक्स क्वेरी की दो अलग-अलग स्थितियों के लिए जवाब देंगे। कोई id = 5
के लिए उत्तर देगा , दूसरा parent_id = @last_id OR parent_id = 5
. के लिए (BTW OR . के साथ कोई समस्या नहीं है उत्तरार्द्ध के अंदर, चूंकि दोनों शब्दों को एक ही अनुक्रमणिका के भीतर से नियंत्रित किया जाता है)।
कोई एकल अनुक्रमणिका नहीं है जो दोनों के लिए उत्तर दे सकती है, और इसलिए FORCE INDEX
निर्देश की अनदेखी की जाती है। देखें, FORCE INDEX
कहते हैं कि MySQL को a . का उपयोग करना है एक टेबल स्कैन पर सूचकांक। इसका मतलब यह नहीं है कि उसे टेबल स्कैन पर एक से अधिक इंडेक्स का उपयोग करना है।
तो MySQL यहां प्रलेखन के नियमों का पालन करता है। लेकिन यह इतना जटिल क्यों है? क्योंकि दोनों इंडेक्स का उपयोग करके उत्तर देने के लिए, MySQL को दोनों से परिणाम इकट्ठा करना होता है, दूसरे को प्रबंधित करते समय कुछ अस्थायी बफर में एक तरफ स्टोर करना होता है। फिर समान पंक्तियों को फ़िल्टर करने के लिए उस बफर पर जाना होगा (यह संभव है कि कुछ पंक्ति सभी स्थितियों में फिट हो)। और फिर उस बफ़र को स्कैन करने के लिए ताकि परिणाम वापस आ सकें।
लेकिन रुकिए, वह बफ़र अपने आप में अनुक्रमित नहीं है। डुप्लिकेट को फ़िल्टर करना कोई स्पष्ट कार्य नहीं है। तो MySQL मूल तालिका पर काम करना पसंद करता है और वहां स्कैन करता है, और उस सारी गड़बड़ी से बचता है।
बेशक यह हल करने योग्य है। Oracle के इंजीनियर अभी भी इसमें सुधार कर सकते हैं (हाल ही में वे क्वेरी निष्पादन योजनाओं को बेहतर बनाने के लिए कड़ी मेहनत कर रहे हैं), लेकिन मुझे नहीं पता कि यह TODO कार्य पर है, या यदि इसकी उच्च प्राथमिकता है।