6

का उपयोग न करने वाले क्वेरी चर के साथ चयन करें मैं स्थानीय चर के उपयोग से एक पुनरावर्ती क्वेरी के साथ एक साधारण आसन्नता सूची में नोड्स के पेड़ को पुनर्प्राप्त करने के साथ (रुचि से बाहर) खेल रहा था।इंडेक्स

मेरे पास अब तक का समाधान मजेदार है लेकिन मुझे आश्चर्य है (और यह मेरा एकमात्र सवाल है) क्यों MySQL इस क्वेरी को अनुकूलित करने के लिए INDEX का उपयोग करने से इंकार कर देता है। क्या MySQL INDEX का उपयोग कर निकटतम बच्चे को देखने में सक्षम नहीं होना चाहिए?

मुझे उत्सुकता है कि MySQL क्यों नहीं करता है। यहां तक ​​कि जब मैं FORCE INDEX का उपयोग करता हूं तो निष्पादन योजना नहीं बदली जाती है। ,

SELECT 
    @last_id := id AS id, 
    parent_id, 
    name, 
    @depth := IF(parent_id = 5, 1, @depth + 1) AS depth 
FROM 
    tree FORCE INDEX (index_parent_id, PRIMARY, index_both), 
    (SELECT @last_id := 5, @depth := -1) vars 
WHERE id = 5 OR parent_id = @last_id OR parent_id = 5 

Try live example at SQLfiddle

ध्यान दें कि कारण छोटे डाटासेट नहीं किया जा सकता है क्योंकि:

यह अब तक, क्वेरी है 5 माता पिता नोड के आईडी होने के साथ जब मैं FORCE INDEX (id) या FORCE INDEX (parent_id) या FORCE INDEX (id, parent_id) निर्दिष्ट करता हूं तो व्यवहार नहीं बदलेगा ...

डॉक्स कहते हैं:

तुम भी बल सूचकांक है, जो उपयोग सूचकांक (index_list) की तरह काम करता उपयोग कर सकते हैं लेकिन इसके अलावा कि एक मेज स्कैन बहुत महंगा माना जाता है के साथ। दूसरे शब्दों में, तालिका स्कैन का उपयोग केवल तभी किया जाता है जब तालिका में पंक्तियों को खोजने के लिए दिए गए इंडेक्स में से किसी एक का उपयोग करने का कोई तरीका न हो।

ऐसा कुछ होना चाहिए जो इंडेक्स का उपयोग करने में असमर्थ क्वेरी को प्रस्तुत करता हो, लेकिन मुझे समझ में नहीं आता कि यह क्या है।


अस्वीकरण: मैं जानता हूँ कि वहाँ की दुकान और SQL में श्रेणीबद्ध डेटा पुनः प्राप्त करने के लिए विभिन्न तरीके हैं। मैं नेस्टेड सेट मॉडल के बारे में जानता हूं। मैं एक वैकल्पिक कार्यान्वयन की तलाश नहीं कर रहा हूं। मैं नेस्टेड सेट की तलाश नहीं कर रहा हूं।

मुझे यह भी पता अपने आप में क्वेरी पागल है और गलत परिणाम पैदा करता है।

मैं बस समझना चाहता हूं (विस्तार से) क्यों MySQL इस मामले में INDEX का उपयोग नहीं कर रहा है।

+0

कभी-कभी किसी तालिका में इतने कम रिकॉर्ड होते हैं कि यह पूरी तालिका को पढ़ने के बजाय इंडेक्स का उपयोग करने के लिए अधिक ओवरहेड होता है। – Randy

+0

@randy अब एक व्यावहारिक तर्क है ... – xandercoded

+0

@Randy अद्यतन प्रश्न देखें – Kaii

उत्तर

2

कारण कहां खंड में या की स्थिति के उपयोग के भीतर निहित है।

+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+ 
| 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 = 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 एक ही क्वेरी में एकाधिक अनुक्रमणिका को संभालने के साथ बहुत अच्छा नहीं है। हालात और शर्तों के साथ चीजें थोड़ा बेहतर हैं; index union अनुकूलन की तुलना में index_merge ऑप्टिमाइज़ेशन देखने की अधिक संभावना है।

चीजें संस्करणों के रूप में उन्नत हो रही हैं, लेकिन मैंने आपको नवीनतम 5.5 पर क्वेरी का परीक्षण किया है, जो वर्तमान नवीनतम उत्पादन संस्करण पर है, और परिणाम जैसा आप वर्णन करते हैं।

यह समझाने के लिए कि यह क्यों मुश्किल है, इस पर विचार करें: दो अलग-अलग इंडेक्स क्वेरी के दो अलग-अलग स्थितियों के उत्तर देंगे। id = 5 के लिए उत्तर देगा, दूसरा parent_id = @last_id OR parent_id = 5 (बीटीडब्ल्यू या के बाद कोई समस्या नहीं है, क्योंकि दोनों शर्तों को उसी इंडेक्स के भीतर से संभाला जाता है)।

कोई भी अनुक्रमणिका नहीं है जो दोनों के लिए उत्तर दे सकती है, और इसलिए FORCE INDEX निर्देश को अनदेखा किया जाता है। देखें, FORCE INDEX का कहना है कि MySQL को तालिका स्कैन पर अनुक्रमणिका का उपयोग करना है। इसका मतलब यह नहीं है कि इसे टेबल स्कैन पर एक से अधिक इंडेक्स का उपयोग करना होगा।

तो MySQL यहां दस्तावेज़ों के नियमों का पालन करता है। लेकिन यह इतना जटिल क्यों है? दोनों इंडेक्स का उपयोग करने के जवाब देने के कारण, MySQL को दोनों के परिणामों को इकट्ठा करना है, दूसरे के प्रबंधन के दौरान किसी अस्थायी बफर में किसी को एक तरफ स्टोर करना है। फिर समान पंक्तियों को फ़िल्टर करने के लिए उस बफर पर जाना होगा (यह संभव है कि कुछ पंक्ति सभी स्थितियों को फिट करे)। और उसके बाद उस बफर को स्कैन करने के लिए ताकि परिणाम वापस कर सकें।

लेकिन प्रतीक्षा करें, कि बफर स्वयं ही अनुक्रमित नहीं है। डुप्लिकेट फ़िल्टर करना एक स्पष्ट कार्य नहीं है। तो MySQL मूल तालिका पर काम करना पसंद करता है और वहां स्कैन करता है, और उस गड़बड़ी से बचें।

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

+0

इस विस्तृत उत्तर के लिए आपको बहुत बहुत धन्यवाद! – Kaii

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