MySql में VARCHAR मैदान पर संभावित INDEX


40

मैं एक MySql डेटाबेस में काम कर रहा हूँ , इस तरह से एक तालिका के साथ:

+--------------+
|  table_name  |
+--------------+
|    myField   |
+--------------+

... और मुझे इस तरह के बहुत सारे प्रश्न करने की आवश्यकता है (सूची में 5-10 तार के साथ) :

SELECT myField FROM table_name
WHERE myField IN ('something', 'other stuff', 'some other a bit longer'...)

लगभग 24.000.000 अद्वितीय पंक्तियाँ होंगी

1) क्या मुझे अपने लिए एक FULLTEXTया INDEXकुंजी का उपयोग करना चाहिए VARCHAR(150)?
2) अगर मैं चार्ट को 150 से बढ़ाकर 220 या 250 कर दूं ... तो इससे बहुत फर्क पड़ेगा? (क्या इसकी गणना करने का कोई तरीका है?)
3) जैसा कि मैंने कहा, वे अद्वितीय होने जा रहे हैं, इसलिए myField एक प्राथमिक कुंजी होना चाहिए । क्या उस क्षेत्र में प्राथमिक कुंजी जोड़ना दुर्लभ नहीं है जो पहले से ही वर्कशेड / FULLTEXT है?


आपको विशिष्टता के लिए PRIMARY का उपयोग करने की आवश्यकता नहीं है। उसके लिए पहले से ही UNIQUE मौजूद है।
कोमराधोमेर

जवाबों:


62

मानक # 1: मानक अनुक्रमण

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    key (myfield)
);

यदि आप इस तरह इंडेक्स करते हैं, तो आप या तो पूरे स्ट्रिंग को देख सकते हैं या लेफ्ट-ओरिएंटेड LIKE सर्च कर सकते हैं

उत्तर # 2: पूर्ण अनुक्रमण

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    fulltext (myfield)
);

आप अलग-अलग कीवर्ड के साथ-साथ संपूर्ण वाक्यांशों की खोजों का प्रभावी ढंग से उपयोग कर सकते हैं। आपको एक कस्टम स्टॉपवर्ड सूची को परिभाषित करने की आवश्यकता होगी क्योंकि MySQL 543 शब्दों को अनुक्रमित नहीं करेगा

यहाँ FULLTEXT इंडेक्स पर पिछले दो सालों से मेरी अन्य पोस्ट हैं

उत्तर # 3: हैश इंडेक्सिंग

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    hashmyfield char(32) not null,
    primary key (id),
    key (hashmyfield)
);

यदि आप एक विशिष्ट मूल्य की तलाश कर रहे हैं और वे मूल्य 32 वर्णों से अधिक हो सकते हैं, तो आप हैश मान संग्रहीत कर सकते हैं:

INSERT INTO mytable (myfield,hashmyfield)
VALUES ('whatever',MD5('whatever'));

इस तरह, आप परिणाम प्राप्त करने के लिए हैश मानों की खोज करते हैं

SELECT * FROM mytable WHERE hashmyfield = MD5('whatever');

कोशिश तो करो !!!


मेरे पास आपके उत्तर को वोट करने के लिए प्रतिष्ठा नहीं है, लेकिन मुझे कहना होगा कि यह महान था। स्पष्टीकरण और उदाहरण के लिए धन्यवाद। मुझे लगता है कि हैश इंडेक्सिंग मेरे मामले के लिए सबसे अच्छा है, यह एक भयानक समाधान है। लेकिन फिर भी एक सवाल: आपको क्या लगता है कि तालिका में तेजी से खोजों के लिए पंक्तियों की सीमा क्या है? [खोजों के लिए कुंजी VARCHAR (32) का उपयोग करते हुए]
मार्क टॉवर

2
यहाँ हैश विकल्प अभी भी एक पाठ है और वास्तव में 16 बाइट्स के लिए 32 बाइट्स हैं। आप कनविनिएंट (बाएं (md5 ('जो भी हो)), 16), 16, -10 () के साथ बिगिन्ट फ़ील्ड का उपयोग कर सकते हैं। वहाँ एक 16 बाइट संख्यात्मक नहीं है, लेकिन आप md5 के आधे पर्याप्त मिल सकता है और फिर यह सूचकांक में केवल 8 बाइट्स है
atxdba

1
एमडी 5 या एसएचए 1 का उपयोग करना अच्छा नहीं है ताकि स्ट्रिंग्स का उत्पादन किया जा सके। MD5 या SHA1 जैसे हैशिंग कार्यों द्वारा उत्पादित स्ट्रिंग्स का वितरण एक बड़ी जगह में यादृच्छिक होता है जो आपके सूचकांक की दक्षता कम कर देता है, जो INSERT और SELECT स्टेटमेंट्स को धीमा कर सकता है। यहाँ यह समझाते हुए पोस्ट किया गया है: code-epicenter.com/…
Mr.M

मैं माफी चाहता हूं क्योंकि यह एक पुराना धागा है, लेकिन मेरा सवाल सीधे तौर पर इससे जुड़ा है, लेकिन मैं उपरोक्त और इसी तरह के अन्य लेखों को पढ़ने से अपनी जरूरतों के लिए स्पष्ट जवाब नहीं दे पा रहा हूं। मेरा परिदृश्य यह है: मैं एक बहुत अल्पविकसित स्टॉक प्रणाली विकसित कर रहा हूं जिसमें अभी के लिए केवल एक तालिका है। यह एक एपीआई के माध्यम से बाहरी रूप से एक्सेस किया जाता है, इसलिए सभी कॉन्फ़िगरेशन कहीं और रखे जाते हैं - यही कारण है कि हमें केवल एक टेबल की आवश्यकता है। जिन दो स्तंभों को मैं अनुक्रमण के बारे में सोच रहा हूं, उनमें लगभग 200 अद्वितीय प्रविष्टियाँ होंगी, जिनकी लंबाई <20 वर्ण होगी। क्या मुझे सूचकांक जोड़ने पर विचार करना चाहिए?
माइक

क्या यह वाम-उन्मुख खोज की तरह है like 'a%'?
एकाउंटेंट एनएन

18

MySQL आपको पूर्वनिर्धारित सूचकांक को परिभाषित करने में सक्षम बनाता है जिसका अर्थ है कि आप मूल स्ट्रिंग से पहले एन वर्णों को अनुक्रमित करने के लिए परिभाषित करते हैं, और चाल एक संख्या एन को चुनने के लिए है जो अच्छी चयनात्मकता देने के लिए पर्याप्त है, लेकिन अंतरिक्ष को बचाने के लिए काफी कम है। उपसर्ग अनुक्रमणिका को लगभग उतना ही उपयोगी बनाने के लिए पर्याप्त होना चाहिए जितना कि यह होगा कि आप पूरे कॉलम को अनुक्रमित करेंगे।

इससे पहले कि हम आगे बढ़ें हम कुछ महत्वपूर्ण शब्दों को परिभाषित करें। सूचकांक चयनात्मकता कुल अलग-अलग अनुक्रमित मूल्यों और कुल पंक्तियों की संख्या का अनुपात है । यहाँ परीक्षण तालिका के लिए एक उदाहरण है:

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+

यदि हम केवल पहले वर्ण (N = 1) को अनुक्रमित करते हैं, तो सूचकांक तालिका निम्न तालिका की तरह दिखाई देगी:

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+

इस मामले में, सूचकांक चयनात्मकता आईएस = 1/3 = 0.33 के बराबर है।

आइए अब देखें कि यदि हम अनुक्रमित वर्णों की संख्या को दो (N = 2) तक बढ़ाते हैं तो क्या होगा।

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+

इस परिदृश्य में IS = 2/3 = 0.66 जिसका अर्थ है कि हमने इंडेक्स चयनात्मकता में वृद्धि की है, लेकिन हमने इंडेक्स का आकार भी बढ़ाया है। ट्रिक न्यूनतम संख्या एन को खोजने के लिए है जिसके परिणामस्वरूप अधिकतम सूचकांक चयनात्मकता होगी

दो दृष्टिकोण हैं जो आप अपने डेटाबेस तालिका के लिए गणना कर सकते हैं। मैं इस डेटाबेस डंप पर प्रदर्शन करूंगा ।

मान लें कि हम तालिका कर्मचारियों में तालिका last_name को अनुक्रमणिका में जोड़ना चाहते हैं , और हम सबसे छोटी संख्या N को परिभाषित करना चाहते हैं जो सर्वोत्तम सूचकांक चयनात्मकता का उत्पादन करेगा।

पहले हमें सबसे अंतिम नामों की पहचान करें:

select count(*) as cnt, last_name from employees group by employees.last_name order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)

जैसा कि आप देख सकते हैं, सबसे अंतिम नाम बाबा है। अब हम पांच अक्षर वाले उपसर्गों के साथ सबसे अधिक बार होने वाले last_name उपसर्गों को खोजने जा रहे हैं ।

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)

हर उपसर्ग की बहुत अधिक घटनाएं होती हैं, जिसका अर्थ है कि हमें संख्या एन को बढ़ाना होगा जब तक कि मान लगभग पिछले उदाहरण के समान न हों।

यहाँ एन = 9 के लिए परिणाम हैं

select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+

यहां एन = 10 के लिए परिणाम हैं।

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)

यह बहुत अच्छे परिणाम हैं। इसका अर्थ है कि हम केवल 10 वर्णों के अनुक्रमण के साथ कॉलम last_name पर अनुक्रमणिका बना सकते हैं । तालिका परिभाषा कॉलम में last_name को VARCHAR(16)इस रूप में परिभाषित किया गया है , और इसका अर्थ है कि हमने प्रति प्रविष्टि में 6 बाइट्स (या यदि अंतिम नाम में UTF8 वर्ण हैं) को सहेज लिया है। इस तालिका में १६३ distinct अलग-अलग मूल्य हैं जिन्हें ६ बाइट से गुणा किया जाता है, लगभग ९ केबी है, और कल्पना करें कि यदि हमारी तालिका में लाखों पंक्तियाँ हैं तो यह संख्या कैसे बढ़ेगी।

आप मेरी पोस्ट में N की संख्या की गणना करने के अन्य तरीकों को पढ़ सकते हैं MySQL में पूर्वनिर्धारित अनुक्रमित

MD5 और SHA1 फ़ंक्शन का उपयोग उन मूल्यों को उत्पन्न करने के लिए किया जाता है जिन्हें अनुक्रमित किया जाना चाहिए, यह भी अच्छा तरीका नहीं है । क्यूं कर? इसे पोस्ट में पढ़ें MySQL डेटाबेस में एक प्राथमिक कुंजी के लिए सही डेटा प्रकार कैसे चुनें


यह एक अलग सवाल का एक बहुत ही मौखिक जवाब है।
मस्टीको

1
क्या आप मेरे साथ मजाक कर रहे हैं?
श्री एम.एम.

क्या आप समझा सकते हैं कि क्या गलत है, या क्या सवाल पर लागू नहीं किया जा सकता है?
मिस्टर एमएम

2
अरे मिस्टर। मुझे वास्तव में आपका उत्तर पसंद है। क्यूं कर ? अपने पुराने उत्तर में, मैंने SUGGESTION # 1: में कहा If you index like this, you can either look for the whole string or do left-oriented LIKE searches। मैंने SUGGESTION # 3: में भी कहा If you are looking for one specific value and those values could be lengths well beyond 32 characters, you could store the hash value:। आपका उत्तर पर्याप्त रूप से प्रदर्शित करता है कि किसी को विशाल कुंजियों का उपयोग क्यों नहीं करना चाहिए और सबसे बाएं अक्षरों पर अनुक्रमित करना चाहिए, जिससे प्रदर्शन में अंतर आ सकता है। आपका जवाब यहाँ है। आपके उत्तर के लिए +1 और DBA StackExchange में आपका स्वागत है।
रोलैंडमाइसीडीडीबीए 20
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.