MySQL में NULL मान वाले स्तंभों के लिए अनुक्रमणिका कैसे डिज़ाइन करें?


11

मेरे पास 40 मिलियन प्रविष्टियों के साथ एक डेटाबेस है और निम्नलिखित WHEREक्लॉज के साथ प्रश्नों को चलाना चाहते हैं

...
WHERE
  `POP1` IS NOT NULL 
  && `VT`='ABC'
  && (`SOURCE`='HOME')
  && (`alt` RLIKE '^[AaCcGgTt]$')
  && (`ref` RLIKE '^[AaCcGgTt]$')
  && (`AA` RLIKE '^[AaCcGgTt]$')
  && (`ref` = `AA` || `alt` = `AA`)
LIMIT 10 ;

POP1एक फ्लोट कॉलम है जो NULL भी हो सकता है। POP1 IS NOT NULLलगभग 50% प्रविष्टियों को बाहर करना चाहिए, इसीलिए मैंने इसे शुरुआत में रखा। अन्य सभी शब्द केवल संख्या को मामूली रूप से कम करते हैं।

दूसरों के बीच, मैंने एक इंडेक्स डिज़ाइन किया pop1_vt_source, जिसका उपयोग नहीं किया गया लगता है, जबकि vtपहले कॉलम के साथ एक इंडेक्स का उपयोग किया जाता है। व्याख्या-आउटपुट:

| id | select_type | table | type | possible_keys                          | key                 | key_len | ref         | rows     | Extra       |
|  1 | SIMPLE      | myTab | ref  | vt_source_pop1_pop2,pop1_vt_source,... | vt_source_pop1_pop2 | 206     | const,const | 20040021 | Using where |

pop1पहले कॉलम के रूप में इंडेक्स का उपयोग क्यों नहीं किया जाता है? की वजह से NOTया की वजह से NULLसामान्य रूप में। मैं अपने सूचकांकों और WHERE क्लॉस के डिजाइन को कैसे बेहतर बना सकता हूं? 10 प्रविष्टियों तक सीमित होने पर भी, क्वेरी को 30 सेकंड से अधिक समय लगता है, हालांकि तालिका में पहले 100 प्रविष्टियों में 10 मैच होने चाहिए।

जवाबों:


10

यह है NOT NULL:

CREATE TEMPORARY TABLE `myTab` (`notnul` FLOAT, `nul` FLOAT);
INSERT INTO `myTab` VALUES (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2);
SELECT * FROM `myTab`;

देता है:

+--------+------+
| notnul | nul  |
+--------+------+
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
+--------+------+

सूचकांक बनाएँ:

CREATE INDEX `notnul_nul` ON `myTab` (`notnul`, `nul`);
CREATE INDEX `nul_notnul` ON `myTab` (`nul`, `notnul`);

SHOW INDEX FROM `myTab`;

देता है:

+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| myTab |          1 | notnul_nul |            1 | notnul      | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
| myTab |          1 | notnul_nul |            2 | nul         | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
| myTab |          1 | nul_notnul |            1 | nul         | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
| myTab |          1 | nul_notnul |            2 | notnul      | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

अब चयनों की व्याख्या करें। ऐसा लगता है कि MySQL इंडेक्स का उपयोग करता है, भले ही आप उपयोग करें NOT NULL:

EXPLAIN SELECT * FROM `myTab` WHERE `notnul` IS NOT NULL;
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+ 
| id | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+ 
|  1 | SIMPLE      | myTab | index | notnul_nul    | notnul_nul | 10      | NULL |   12 | Using where; Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+


EXPLAIN SELECT * FROM `myTab` WHERE `nul` IS NOT NULL;
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | myTab | range | nul_notnul    | nul_notnul | 5       | NULL |    6 | Using where; Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+

लेकिन, जब तुलना NOT NULLऔर NULL, ऐसा लगता है कि MySQL का उपयोग करते समय अन्य अनुक्रमित पसंद करता है NOT NULL। हालांकि यह स्पष्ट रूप से कोई जानकारी नहीं जोड़ता है। ऐसा इसलिए है क्योंकि MySQL NOT NULLएक सीमा के रूप में व्याख्या करता है जैसा कि आप टाइप-कॉलम में देख सकते हैं। मुझे यकीन नहीं है अगर कोई वर्कअराउंड है:

EXPLAIN SELECT * FROM `myTab` WHERE `nul` IS NULL && notnul=2;
+----+-------------+-------+------+-----------------------+------------+---------+-------------+------+--------------------------+
| id | select_type | table | type | possible_keys         | key        | key_len | ref         | rows | Extra                    |
+----+-------------+-------+------+-----------------------+------------+---------+-------------+------+--------------------------+
|  1 | SIMPLE      | myTab | ref  | notnul_nul,nul_notnul | notnul_nul | 10      | const,const |    1 | Using where; Using index |
+----+-------------+-------+------+-----------------------+------------+---------+-------------+------+--------------------------+


EXPLAIN SELECT * FROM `myTab` WHERE `nul` IS NOT NULL && notnul=2;
+----+-------------+-------+-------+-----------------------+------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys         | key        | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+-----------------------+------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | myTab | range | notnul_nul,nul_notnul | notnul_nul | 10      | NULL |    1 | Using where; Using index |
+----+-------------+-------+-------+-----------------------+------------+---------+------+------+--------------------------+

मुझे लगता है कि MySQL में एक बेहतर कार्यान्वयन हो सकता है, क्योंकि NULLएक विशेष मूल्य है। संभवतः अधिकांश लोग NOT NULLमूल्यों में रुचि रखते हैं।


3

समस्या NULL मान नहीं है। यह सूचकांक की चयनात्मकता है। आपके उदाहरण में, की चयनात्मकता source, pop1सिर्फ की चयनात्मकता से बेहतर है pop1। यह whereक्लॉज़ में अधिक स्थितियों को शामिल करता है, इसलिए पेज हिट को कम करने की अधिक संभावना है।

आप सोच सकते हैं कि पंक्तियों की संख्या को 50% तक कम करना पर्याप्त है, लेकिन यह वास्तव में नहीं है। एक whereखंड में अनुक्रमित होने का लाभ पढ़ने वाले पृष्ठों की संख्या को कम करना है। यदि किसी पृष्ठ में औसतन, कम से कम एक रिकॉर्ड गैर-पूर्ण मान के साथ है, तो सूचकांक का उपयोग करने का कोई लाभ नहीं है। और, अगर प्रति पृष्ठ 10 रिकॉर्ड हैं, तो लगभग हर पृष्ठ में उन रिकॉर्डों में से एक होगा।

आप एक सूचकांक पर कोशिश कर सकते हैं (pop1, vt, source)। आशावादी को उस एक को चुनना चाहिए।

अंत में, हालांकि, यदि whereक्लॉज रिकॉर्ड खो गया है - कोई नियम नहीं है, लेकिन मान लें कि 20% है - तो सूचकांक शायद मदद नहीं करेगा। एक अपवाद तब होगा जब सूचकांक में क्वेरी द्वारा आवश्यक सभी कॉलम होंगे। फिर यह प्रत्येक रिकॉर्ड के लिए डेटा पृष्ठ में लाए बिना क्वेरी को संतुष्ट कर सकता है।

और, यदि किसी इंडेक्स का उपयोग किया जाता है और चयनात्मकता अधिक है, तो इंडेक्स के साथ प्रदर्शन इसके बिना प्रदर्शन से भी बदतर हो सकता है।


मुझे लगता है कि यह वास्तव में वह पर्वतमाला है जो अंतर का कारण बनती है (मेरा उत्तर देखें)। हालांकि मुझे लगता है कि इसे MySQL में बेहतर तरीके से लागू किया जा सकता है, क्योंकि ज्यादातर लोग NOT NULLकॉलम में रुचि रखते हैं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.