2011-09-29 12 views
10

मैं निम्नलिखित MySQL तालिका (सरलीकृत) है:MySQL में इस अनुक्रमणिका को हटाने से मेरी क्वेरी 100x तेज हो जाती है?

CREATE TABLE `track` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `title` varchar(256) NOT NULL, 
    `is_active` tinyint(1) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `is_active` (`is_active`, `id`) 
) ENGINE=MyISAM AUTO_INCREMENT=7495088 DEFAULT CHARSET=utf8 

'is_active' कॉलम पंक्तियों को मैं सबसे में अनदेखा करना चाहते निशान, लेकिन सभी नहीं, मेरे प्रश्नों की। मेरे पास कुछ प्रश्न हैं जो समय-समय पर इस तालिका से बाहर निकलते हैं। उनमें से एक इस तरह दिखता है:

SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10; 

यह क्वेरी निष्पादित करने में एक मिनट से अधिक समय लेती है। यहाँ कार्य योजना लागू है:

> EXPLAIN SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10; 
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+ 
| 1 | SIMPLE  | t  | ref | PRIMARY,is_active | is_active | 1  | const | 3747543 | Using where | 
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+ 

अब, अगर मैं MySQL बता 'is_active' सूचकांक अनदेखी करने के लिए, क्वेरी तत्क्षण होता है।

> EXPLAIN SELECT id,title from track IGNORE INDEX(is_active) WHERE (track.is_active=1 AND track.id > 5580702) ORDER BY id ASC LIMIT 10; 
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+ 
| 1 | SIMPLE  | t  | range | PRIMARY  | PRIMARY | 4  | NULL | 1597518 | Using where | 
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+ 

अब, क्या वास्तव में अजीब बात है कि अगर मैं बल MySQL 'is_active' सूचकांक का उपयोग करने, क्वेरी एक बार फिर से तत्क्षण होता है!

+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+ 
| 1 | SIMPLE  | t  | range | is_active  |is_active| 5  | NULL | 1866730 | Using where | 
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+ 

मैं सिर्फ इस व्यवहार समझ में नहीं आता। 'Is_active' इंडेक्स में, पंक्तियों को is_active द्वारा क्रमबद्ध किया जाना चाहिए, आईडी के बाद। मैं अपनी क्वेरी में 'is_active' और 'id' कॉलम दोनों का उपयोग करता हूं, इसलिए ऐसा लगता है कि आईडी को खोजने के लिए केवल पेड़ के चारों ओर कुछ हॉप करने की आवश्यकता है, फिर तालिका से शीर्षक प्राप्त करने के लिए उन आईडी का उपयोग करें।

क्या चल रहा है?

संपादित करें: अधिक जानकारी मैं क्या कर रहा हूँ पर:

  • क्वेरी कैश विकलांग
  • रनिंग अनुकूलन टेबल है और विश्लेषण तालिका कोई प्रभाव नहीं
  • 6.620.372 पंक्तियों है 'is_active' सही पर सेट किया था। 874,714 पंक्तियों में गलत है 'is_active' सेट है।
  • फोर्स INDEX (is_active) का उपयोग करके एक बार फिर क्वेरी को गति देता है।
  • MySQL संस्करण 5.1.54
+2

आप बेंचमार्किंग से पहले कैश साफ़ कर रहे हैं, है ना? – dfb

+0

यह भी सुनिश्चित करें कि तालिका के आंकड़े चालू हैं और सूचकांक पुनर्निर्मित हैं। (हालांकि यह MySQL में किया गया है ;-) –

+0

यदि आप WHERE शर्तों को उलट देते हैं तो क्या होता है? 'जहां (track.id> 5580702 और track.is_active = 1)' – EJP

उत्तर

7

ऐसा लगता है कि MySQL इंडेक्स का उपयोग करने के बारे में एक खराब निर्णय ले रहा है।

उस क्वेरी योजना से, यह दिखा रहा है कि यह या तो प्राथमिक या is_active अनुक्रमणिका का उपयोग कर सकता था, और यह track.is_active पहले संकीर्ण करने के लिए is_active चुना गया है। हालांकि, यह केवल इंडेक्स (track.is_active) के पहले कॉलम का उपयोग कर रहा है। यह 3747543 परिणाम प्राप्त करता है जिसे तब फ़िल्टर और क्रमबद्ध किया जाना चाहिए।

यदि उसने प्राथमिक अनुक्रमणिका चुना है, तो यह इंडेक्स का उपयोग करके 15 9 7518 पंक्तियों को कम करने में सक्षम होगा, और उन्हें पहले से track.id के क्रम में पुनर्प्राप्त किया जाएगा, जिसके लिए आगे कोई सॉर्टिंग की आवश्यकता नहीं है। वह तेज़ होगा।

नई जानकारी:

तीसरे मामले जहां FORCE INDEX उपयोग कर रहे हैं, MySQL is_active सूचकांक लेकिन अब उपयोग कर रहा है केवल, पहले कॉलम का उपयोग करते हुए यह दोनों कॉलम (key_len देखें) का उपयोग कर रहा है के बजाय। इसलिए अब यह एक ही इंडेक्स का उपयोग कर आईडी द्वारा निष्क्रिय और सॉर्ट और फिल्टर द्वारा संकीर्ण करने में सक्षम है, और चूंकि is_active एक स्थिर है, ऑर्डर बीई दूसरे कॉलम से संतुष्ट है (यानी इंडेक्स की एक शाखा से पंक्तियां पहले से ही हैं क्रमबद्ध क्रम में)। यह प्राथमिकता का उपयोग करने से भी एक बेहतर परिणाम प्रतीत होता है - और शायद आप पहले स्थान पर क्या चाहते थे, है ना?

मुझे नहीं पता कि यह फोर्स इंडेक्स के बिना इस इंडेक्स के दोनों कॉलम का उपयोग क्यों नहीं कर रहा था, जब तक कि बीच में सूक्ष्म तरीके से क्वेरी बदल नहीं जाती। यदि नहीं, तो मैं इसे गलत निर्णय लेने के लिए MySQL पर डाल दूंगा।

+0

बेशक, यदि आप MySQL से बेहतर जानते हैं तो आप हमेशा [USE INDEX()] (http://dev.mysql.com/doc/refman/5.5/en/index-hints.html) का उपयोग कर सकते हैं यह सुझाव देने के लिए कि यह कौन सा अनुक्रमणिका है पसंद करना चाहिए आप MySQL को अपने आप को समझने का मौका देने के लिए [एनालिज टेबल] (http://dev.mysql.com/doc/refman/5.5/en/analyze-table.html) भी आज़मा सकते हैं, जो कभी-कभी काम कर सकता है । – thomasrutter

+0

यदि मैं फोर्स इंडेक्स (is_active) का उपयोग करता हूं तो क्वेरी तत्काल होती है (हालिया संपादन देखें)। कोई विचार? – cwick

+0

मुझे यकीन नहीं है - संभवतः किसी प्रकार का कैश? शायद इसके लिए EXPLAIN आउटपुट जोड़ें? क्या आपको वही आउटपुट मिलता है, उसी क्रम में? – thomasrutter

1

मुझे लगता है कि speedup अपने जहां खंड के कारण है। मुझे लगता है कि यह केवल पूरी बड़ी तालिका में पंक्तियों का एक छोटा सबसेट पुनर्प्राप्त कर रहा है। बड़ी इंडेक्स फ़ाइल के माध्यम से फ़िल्टरिंग करने की तुलना में छोटे सबसेट पर is_active के लिए पुनर्प्राप्त डेटा का टेबल स्कैन करना तेज़ है। संयुक्त सूचकांक को घुमाने की तुलना में एक कॉलम इंडेक्स का ट्रैवर्स करना बहुत तेज़ है।

0

कुछ बातें आप की कोशिश कर सकते:

  • एक अनुकूलित कर सकता हूं और अपनी मेज पर जाँच, इसलिए mysql को पुन: calculate सूचकांक को महत्व देता
  • http://dev.mysql.com/doc/refman/5.1/en/index-hints.html पर एक नजर है - आप mysql बता सही चयन करने के लिए कर सकते हैं विभिन्न मामलों में सूचकांक
संबंधित मुद्दे