MySQL Indexing VarChar


10

मैं blogentriesबेहतर प्रदर्शन के लिए अपने डेटाबेस को अनुक्रमित करने की कोशिश कर रहा हूं, लेकिन एक मुद्दा मिला।

यहाँ संरचना है:

CREATE TABLE IF NOT EXISTS `blogentries` (
  `id_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `title_id` varchar(100) COLLATE latin1_german2_ci NOT NULL,
  `entry_id` varchar(5000) COLLATE latin1_german2_ci NOT NULL,
  `date_id` int(11) NOT NULL,
  PRIMARY KEY (`id_id`)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1
COLLATE=latin1_german2_ci
AUTO_INCREMENT=271;

निम्नलिखित की तरह एक क्वेरी ठीक से सूचकांक का उपयोग करता है:

EXPLAIN SELECT id_id,title_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
| आईडी | select_type | तालिका | प्रकार | possible_keys | कुंजी | key_len | रेफरी | पंक्तियाँ | अतिरिक्त |
+ ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
| 1 | SIMPLE | ब्लॉगजेंट | सूचकांक | नल | PRIMARY | 114 | नल | 126 | इंडेक्स का उपयोग करना |
+ ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +

हालाँकि, जब मैं क्वेरी entry_idमें जोड़ता हूँ तो SELECTयह फाइलसर्ट का उपयोग करता है

EXPLAIN SELECT id_id,title_id,entry_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
| आईडी | select_type | तालिका | प्रकार | possible_keys | कुंजी | key_len | रेफरी | पंक्तियाँ | अतिरिक्त |
+ ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
| 1 | SIMPLE | ब्लॉगजेंट | सभी | नल | नल | नल | नल | 126 | फाइल का उपयोग करना |
+ ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +

मैं सोच रहा था कि ऐसा क्यों हो रहा है और मैं इससे कैसे बच सकता हूं? क्या यह कारण है VarChar, और इसे किसी और चीज़ में बदल दिया जाना चाहिए?

जैसा कि मैं उच्च Handler_read_rndऔर Handler_read_rnd_nextमूल्यों में चल रहा हूं मैं अपने सभी प्रश्नों को सूचकांक का उपयोग करने की कोशिश कर रहा हूं ।

अगर आपको कोई अन्य जानकारी चाहिए तो मैं उसे पोस्ट भी कर सकता हूँ।


filesort का मतलब है कि यह डिस्क पर सॉर्ट कर रहा है।
करमीत

WHERE 1=1अपनी दूसरी क्वेरी में जोड़ने का प्रयास करें ।
केरमिट

MySQL का कौन सा संस्करण है? आपकी सॉर्ट बफर साइज़ ( SELECT @@sort_buffer_size) क्या है?

@njk filesort क्वेरी के 'ORDER BY' भाग का एक परिणाम है

1
@ तशपीमहवा जरूरी नहीं, पहला बयान देखें
Kermit

जवाबों:


6

चूँकि आपके पास WHEREया तो क्वेरी में कोई क्लॉज़ नहीं है , आप दोनों मामलों में सभी पंक्तियों को वापस कर रहे हैं, इसलिए मुझे लगता है कि इंडेक्स के उपयोग या गैर-उपयोग से इन उदाहरणों में प्रदर्शन पर बहुत कम प्रभाव पड़ेगा।


निश्चित रूप से MySQL के लिए सूचकांक का उपयोग करना चाहिए ORDER BY?

@eggyal नहीं अगर यह स्मृति के लिए बहुत बड़ा है।
Kermit

@njk: इसका कोई मतलब नहीं है ... यह पूरी तरह से मेमोरी में लोड करने की आवश्यकता के बिना, सूचकांक को पार कर सकता है। फ़ाइलशूट करने की आवश्यकता के बिना परिणामों को क्रमबद्ध किया जाएगा।

@eggyal मैं के आकार पर सवाल उठाऊंगा varchar(5000)
Kermit

@njk: लेकिन वह कॉलम न तो इंडेक्स में है और न ही सॉर्ट में इस्तेमाल किया जा रहा है।
अहग्याल

2

ORDER BYअनुकूलन के तहत प्रलेखित :

धीमी क्वेरी के लिए जिसका filesortउपयोग नहीं किया गया है, max_length_for_sort_dataउस मूल्य को कम करने का प्रयास करें जो ट्रिगर करने के लिए उपयुक्त है filesort

अपने ब्लॉग लेख में वास्तव में read_rnd_buffer_size क्या है , पीटर ज़ैतसेव बताते हैं:

मेरे लिए इसका मतलब है कि MySQL 4.1 के बाद से इस विकल्प का उपयोग कई प्रकार के मामलों में किया जाता है - यदि आप कुछ फ़ील्ड्स ( max_length_for_sort_data से कम ) डेटा को बफ़र और सॉर्ट फ़ाइल में संग्रहित किया जाना चाहिए, तो चयनित कॉलम के लिए read_rnd_buffer की कोई आवश्यकता नहीं होगी। लंबे होते हैं इसलिए वे max_length_for_sort_data से अधिक लंबे होते हैं, इसका अक्सर मतलब होगा कि उनके बीच कुछ TEXT / BLOB कॉलम हैं। हालाँकि इसका उपयोग तब किया जाएगा यदि बड़ी संख्या में कॉलम हैं या लंबे VARCHAR कॉलम का उपयोग किया जाता है - यह एक पंक्ति बनाने के लिए केवल UTF8 VARCHAR (255) के जोड़े को लेता है जो अपनी स्थिर प्रस्तुति में max_length_for_sort_ata से अधिक लंबा है ।

इससे पता चलता है कि max_length_for_sort_dataस्तंभों के कुल आकार पर एक सीमा है जो एक का चयन कर रहा है, जिसके ऊपर filesortएक इंडेक्स-आधारित सॉर्ट के बजाय उपयोग किया जाएगा।

आपके मामले में, entry_id(5002 बाइट्स) का चयन इस चर के 1KiB डिफ़ॉल्ट मान पर कुल आकार लेता है और इसलिए filesortइसका उपयोग किया जाता है। 8KiB की सीमा बढ़ाने के लिए, आप कर सकते हैं:

SET SESSION max_length_for_sort_data = 8192;

मेरे पास इसकी एक समान स्थापना के साथ एक तालिका है, और यह सेटिंग फ़ाइलों के उपयोग में किसी भी परिवर्तन को ट्रिगर करने के लिए प्रकट नहीं होती है।

@ मफिनिस्टा: यह दिलचस्प है। मुझे लगता है कि यह @ RolandoMySQLDBA के उत्तर के अनुसार कुछ अन्य बफर सेटिंग्स से संबंधित हो सकता है ?
ईग्यगल

2

आपने यहाँ बहुत सी दिलचस्प प्रतिक्रियाएँ प्राप्त की हैं, लेकिन किसी ने भी इस प्रश्न का उत्तर नहीं दिया है - ऐसा क्यों हो रहा है? जैसा कि मैं इसे समझता हूं, जब एक SELECT क्वेरी में MySQL में वैरिएबल लेंथ डेटा होता है, और कोई इंडेक्स नहीं होता है जो सभी अनुरोधित कॉलम से मेल खाता है, तो यह हमेशा एक फाइलशॉट का उपयोग करेगा। डेटा का आकार यहां बहुत प्रासंगिक नहीं है। MySQL डॉक्यूमेंटेशन में इस सवाल का सीधा जवाब खोजना मुश्किल है, लेकिन यहाँ एक अच्छा ब्लॉग पोस्ट है जहाँ कोई व्यक्ति आपके लिए एक समान समस्या का सामना कर रहा है।

इसे भी देखें: MySQL Queries को ऑप्टिमाइज़ करने के 10 टिप्स (जो चूसना नहीं हैं)

इसलिए, यदि इसका व्यवहार्य प्रविष्टि_आईडी पर एक सूचकांक है, तो आप इसे जोड़ सकते हैं और सभी सेट हो सकते हैं। लेकिन मुझे संदेह है कि यह एक विकल्प है, तो क्या करना है?

इस बारे में आपको कुछ करना चाहिए या नहीं, यह एक अलग सवाल है। यह जानना महत्वपूर्ण है कि MySQL में 'filesort' का नाम खराब है - यह वास्तव में इस विशेष क्वेरी को सॉर्ट करने के लिए उपयोग किए जाने वाले एल्गोरिदम का सिर्फ नाम है, और कई मामलों में, सॉर्ट वास्तव में मेमोरी में होगा। यदि आप इस तालिका के बहुत बढ़ने की उम्मीद नहीं करते हैं, तो शायद यह कोई बड़ी बात नहीं है।

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

यहाँ SO पर कुछ अन्य उत्तर दिए गए हैं जो इस प्रश्न के बारे में बात करते हैं:


ओपी की पहली क्वेरी " MySQL में चर लंबाई डेटा शामिल है, और कोई भी सूचकांक नहीं है जो सभी अनुरोधित कॉलम से मेल खाता है ", फिर filesortभी स्पष्ट रूप से उस मामले में उपयोग नहीं किया गया था। मुझे यह भी लगता है कि अकेले में एक छोटी सी मेज को छांटना भी एक अस्वीकार्य प्रदर्शन हिट साबित हो सकता है: उदाहरण के लिए यदि क्वेरी बहुत अधिक की जाती है (और तालिका में परिवर्तन होता है ताकि कैश का उपयोग न किया जा सके)।
१३

मेरे पास इसका परीक्षण करने का समय नहीं है, लेकिन मैं सोच रहा हूं कि क्या यह VARCHAR होने से ट्रिगर होता है, जिसे dev.mysql.com/doc/refman/5.1/en/char में निर्दिष्ट लंबाई के लिए 2 बाइट्स की आवश्यकता होती है । html - तो पहली क्वेरी उस सीमा के भीतर फिट होती है लेकिन दूसरी नहीं।

0

WHEREअपने प्रश्नों में एक खंड जोड़ने का प्रयास करें ।

सूचकांक का उपयोग तब भी किया जा सकता है यदि ORDER BY सूचकांक से बिल्कुल मेल नहीं खाता है, जब तक कि सूचकांक के सभी अप्रयुक्त भाग और सभी अतिरिक्त ORDER BY कॉलम WHERE क्लॉज में स्थिरांक हैं । कुछ मामलों में, MySQL ORDER BY को हल करने के लिए अनुक्रमित का उपयोग नहीं कर सकता है , हालांकि यह अभी भी उन पंक्तियों को खोजने के लिए अनुक्रमित का उपयोग करता है जो WHERE क्लॉज से मेल खाते हैं ।

http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html


लेकिन इस मामले में ORDER BY करता है वास्तव में सूचकांक से मेल खाते हैं, तो एक के लिए कोई जरूरत नहीं है WHEREखंड।

साइट पर वास्तविक क्वेरी में मेरे पास "जहां" खंड है, इसलिए मुझे पता है कि फ़ाइल सॉर्ट का कारण नहीं है। मैं सोच रहा हूँ कि क्या इसका varchar का उपयोग हो रहा है?

0

मेरे ज्ञान की सीमा तक varchar केवल अधिकतम 8000 बाइट्स पकड़ सकता है जो कि लगभग 4000 वर्ण हैं। इस प्रकार, 5000 भंडारण की सीमा को बढ़ाता हुआ प्रतीत होगा, और इस मामले में शायद यही कारण है कि छंटनी गड़बड़ हो रही है।

"varchar [(n। अधिकतम)] चर-लंबाई, गैर-यूनिकोड चरित्र डेटा। n 1 से 8,000 तक का मान हो सकता है। अधिकतम इंगित करता है कि अधिकतम संग्रहण आकार 2 ^ 31-1 बाइट्स है। भंडारण का आकार वास्तविक है। डेटा की लंबाई + 2 बाइट्स दर्ज की गई है। दर्ज किया गया डेटा लंबाई में 0 वर्ण हो सकता है। varchar के लिए SQL-2003 समानार्थी शब्द चार या वर्ण भिन्न होते हैं। "

उम्मीद है कि यह आपके प्रश्न का उत्तर देगा


जैसा कि CHARVARCHARटाइप्स के तहत प्रलेखित किया गया है : " VARCHAR कॉलम में मान चर-लंबाई के तार हैं। लंबाई को MySQL 5.0.3 से पहले 0 से 255 तक और 5.0.3 और बाद के संस्करणों में 0 से 65,535 तक के मान के रूप में निर्दिष्ट किया जा सकता है। प्रभावी VARCHARMySQL 5.0.3 की अधिकतम लंबाई और बाद में अधिकतम पंक्ति आकार (65,535 बाइट्स, जो सभी स्तंभों के बीच साझा की जाती है) और उपयोग किए गए वर्ण सेट के
अधीन है

0

आपकी तालिका में केवल 126 पंक्तियाँ हैं। यहां तक ​​कि अगर हर पंक्ति लगभग 5KB की अधिकतम आकार की है, तो इसका मतलब यह होगा कि डिस्क से पढ़ने के लिए कुल आकार लगभग 600KB है - यह पूरी तरह से नहीं है। फ्रैंक होने के लिए, यह बहुत कम राशि है, शायद अधिकांश आधुनिक डिस्क ड्राइव के कैश आकार से कम है।

अब, यदि सर्वर को आपकी क्वेरी को पूरा करने के लिए आपके डेटा को पुनः प्राप्त करने की आवश्यकता है, तो सबसे महंगा ऑपरेशन इसे डिस्क से पढ़ना है। लेकिन, इंडेक्स ऑर्डर के अनुसार इसे पढ़ना हमेशा ऐसा करने का सबसे तेज़ तरीका नहीं है, खासकर जब डेटा की मात्रा इतनी कम हो।

आपके मामले में, यह डिस्क से एकल तालिका के रूप में डिस्क से पूरे टेबल डेटा को पढ़ने के लिए अधिक कुशल है (शायद केवल एक डिस्क में ऑपरेशन या तलाश है), और फिर इसे क्रमबद्ध करने के लिए RAM में क्रमबद्ध करें BY, जो डिस्क की तुलना में तुरंत है। ऑपरेशन पढ़ें। यदि सर्वर आपके डेटा को इंडेक्स के अनुसार पढ़ता है, तो उसे 126 तक जारी करना होगा (उफ़!) ऑपरेशन पढ़ें, एक ही डेटा फ़ाइल में कई बार आगे और पीछे की मांग करना।

दूसरे शब्दों में, अनुक्रमिक स्कैन हमेशा एक बुरी चीज नहीं है, और mysql आवश्यक रूप से बेवकूफ नहीं है। यदि आप उस सूचकांक का उपयोग करने के लिए mysql को मजबूर करने की कोशिश करते हैं, तो यह आपके द्वारा वर्तमान में अनुक्रमिक स्कैन की तुलना में सबसे अधिक धीमी गति से काम करेगा।

और यही कारण है कि जब 5KB क्षेत्र को शामिल नहीं किया गया था, तो यह सूचकांक का उपयोग कर रहा था, क्योंकि तब पुनर्प्राप्त डेटा तालिका में 99% डेटा का गठन नहीं करता था। जब आपने अपना 5KB फ़ील्ड शामिल किया था, तो अब क्वेरी को 99% डेटा पढ़ना है, और यह पूरी चीज़ को पढ़ने और बाद में मेमोरी में सॉर्ट करने के लिए सस्ता है।


ऐसा लगता है कि आप फुल टेबल स्कैन्स से कैसे बचें, से कई चीजों को गड़बड़ कर रहे हैं , जो संतोषजनक JOINस्थिति और WHEREखंड में सूचकांक के उपयोग के साथ हैं, ORDER BYखंड नहीं ।
इग्यगल

बिल्कुल विपरीत। इस विशेष मामले में फुल टेबल स्कैन अच्छी बात है क्योंकि यह सूचकांक क्रम से पढ़ने की तुलना में तेजी से होता है।

0

MySQL के किस संस्करण का आप उपयोग कर रहे हैं?

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.