कैसे बड़े तालिकाओं पर बाएँ जोड़ों के साथ बहुत धीमी गति से चयन करने के लिए


15

मैं गुगली कर रहा था, आत्म-शिक्षित और घंटों तक समाधान की तलाश कर रहा था लेकिन कोई भाग्य नहीं। मुझे यहां कुछ ऐसे ही सवाल मिले लेकिन यह मामला नहीं।

मेरी टेबल:

  • व्यक्ति (~ 10 मीटर पंक्तियाँ)
  • विशेषताएँ (स्थान, आयु, ...)
  • लिंक (M: M) व्यक्तियों और विशेषताओं (~ 40M पंक्तियों) के बीच

पूर्ण डंप ~ 280MB

स्थिति: मैं person_idकुछ स्थानों ( location.attribute_value BETWEEN 3000 AND 7000), gender.attribute_value = 1कुछ वर्षों में पैदा हुआ ( bornyear.attribute_value BETWEEN 1980 AND 2000) और कुछ आंखों का रंग ( eyecolor.attribute_value IN (2,3)) होने के कारण कुछ स्थानों से सभी व्यक्ति आईडी ( ) का चयन करने की कोशिश करता हूं ।

यह मेरी क्वेरी डायन है 3 ~ 4 मिनट। और मैं अनुकूलित करना चाहूंगा:

SELECT person_id
FROM person
    LEFT JOIN attribute location ON location.attribute_type_id = 1 AND location.person_id = person.person_id
    LEFT JOIN attribute gender ON gender.attribute_type_id = 2 AND gender.person_id = person.person_id
    LEFT JOIN attribute bornyear ON bornyear.attribute_type_id = 3 AND bornyear.person_id = person.person_id
    LEFT JOIN attribute eyecolor ON eyecolor.attribute_type_id = 4 AND eyecolor.person_id = person.person_id
WHERE 1
    AND location.attribute_value BETWEEN 3000 AND 7000
    AND gender.attribute_value = 1
    AND bornyear.attribute_value BETWEEN 1980 AND 2000
    AND eyecolor.attribute_value IN (2,3)
LIMIT 100000;

परिणाम:

+-----------+
| person_id |
+-----------+
|       233 |
|       605 |
|       ... |
|   8702599 |
|   8703617 |
+-----------+
100000 rows in set (3 min 42.77 sec)

विस्तार से बताएं:

+----+-------------+----------+--------+---------------------------------------------+-----------------+---------+--------------------------+---------+----------+--------------------------+
| id | select_type | table    | type   | possible_keys                               | key             | key_len | ref                      | rows    | filtered | Extra                    |
+----+-------------+----------+--------+---------------------------------------------+-----------------+---------+--------------------------+---------+----------+--------------------------+
|  1 | SIMPLE      | bornyear | range  | attribute_type_id,attribute_value,person_id | attribute_value | 5       | NULL                     | 1265229 |   100.00 | Using where              |
|  1 | SIMPLE      | location | ref    | attribute_type_id,attribute_value,person_id | person_id       | 5       | test1.bornyear.person_id |       4 |   100.00 | Using where              |
|  1 | SIMPLE      | eyecolor | ref    | attribute_type_id,attribute_value,person_id | person_id       | 5       | test1.bornyear.person_id |       4 |   100.00 | Using where              |
|  1 | SIMPLE      | gender   | ref    | attribute_type_id,attribute_value,person_id | person_id       | 5       | test1.eyecolor.person_id |       4 |   100.00 | Using where              |
|  1 | SIMPLE      | person   | eq_ref | PRIMARY                                     | PRIMARY         | 4       | test1.location.person_id |       1 |   100.00 | Using where; Using index |
+----+-------------+----------+--------+---------------------------------------------+-----------------+---------+--------------------------+---------+----------+--------------------------+
5 rows in set, 1 warning (0.02 sec)

रूपरेखा:

+------------------------------+-----------+
| Status                       | Duration  |
+------------------------------+-----------+
| Sending data                 |  3.069452 |
| Waiting for query cache lock |  0.000017 |
| Sending data                 |  2.968915 |
| Waiting for query cache lock |  0.000019 |
| Sending data                 |  3.042468 |
| Waiting for query cache lock |  0.000043 |
| Sending data                 |  3.264984 |
| Waiting for query cache lock |  0.000017 |
| Sending data                 |  2.823919 |
| Waiting for query cache lock |  0.000038 |
| Sending data                 |  2.863903 |
| Waiting for query cache lock |  0.000014 |
| Sending data                 |  2.971079 |
| Waiting for query cache lock |  0.000020 |
| Sending data                 |  3.053197 |
| Waiting for query cache lock |  0.000087 |
| Sending data                 |  3.099053 |
| Waiting for query cache lock |  0.000035 |
| Sending data                 |  3.064186 |
| Waiting for query cache lock |  0.000017 |
| Sending data                 |  2.939404 |
| Waiting for query cache lock |  0.000018 |
| Sending data                 |  3.440288 |
| Waiting for query cache lock |  0.000086 |
| Sending data                 |  3.115798 |
| Waiting for query cache lock |  0.000068 |
| Sending data                 |  3.075427 |
| Waiting for query cache lock |  0.000072 |
| Sending data                 |  3.658319 |
| Waiting for query cache lock |  0.000061 |
| Sending data                 |  3.335427 |
| Waiting for query cache lock |  0.000049 |
| Sending data                 |  3.319430 |
| Waiting for query cache lock |  0.000061 |
| Sending data                 |  3.496563 |
| Waiting for query cache lock |  0.000029 |
| Sending data                 |  3.017041 |
| Waiting for query cache lock |  0.000032 |
| Sending data                 |  3.132841 |
| Waiting for query cache lock |  0.000050 |
| Sending data                 |  2.901310 |
| Waiting for query cache lock |  0.000016 |
| Sending data                 |  3.107269 |
| Waiting for query cache lock |  0.000062 |
| Sending data                 |  2.937373 |
| Waiting for query cache lock |  0.000016 |
| Sending data                 |  3.097082 |
| Waiting for query cache lock |  0.000261 |
| Sending data                 |  3.026108 |
| Waiting for query cache lock |  0.000026 |
| Sending data                 |  3.089760 |
| Waiting for query cache lock |  0.000041 |
| Sending data                 |  3.012763 |
| Waiting for query cache lock |  0.000021 |
| Sending data                 |  3.069694 |
| Waiting for query cache lock |  0.000046 |
| Sending data                 |  3.591908 |
| Waiting for query cache lock |  0.000060 |
| Sending data                 |  3.526693 |
| Waiting for query cache lock |  0.000076 |
| Sending data                 |  3.772659 |
| Waiting for query cache lock |  0.000069 |
| Sending data                 |  3.346089 |
| Waiting for query cache lock |  0.000245 |
| Sending data                 |  3.300460 |
| Waiting for query cache lock |  0.000019 |
| Sending data                 |  3.135361 |
| Waiting for query cache lock |  0.000021 |
| Sending data                 |  2.909447 |
| Waiting for query cache lock |  0.000039 |
| Sending data                 |  3.337561 |
| Waiting for query cache lock |  0.000140 |
| Sending data                 |  3.138180 |
| Waiting for query cache lock |  0.000090 |
| Sending data                 |  3.060687 |
| Waiting for query cache lock |  0.000085 |
| Sending data                 |  2.938677 |
| Waiting for query cache lock |  0.000041 |
| Sending data                 |  2.977974 |
| Waiting for query cache lock |  0.000872 |
| Sending data                 |  2.918640 |
| Waiting for query cache lock |  0.000036 |
| Sending data                 |  2.975842 |
| Waiting for query cache lock |  0.000051 |
| Sending data                 |  2.918988 |
| Waiting for query cache lock |  0.000021 |
| Sending data                 |  2.943810 |
| Waiting for query cache lock |  0.000061 |
| Sending data                 |  3.330211 |
| Waiting for query cache lock |  0.000025 |
| Sending data                 |  3.411236 |
| Waiting for query cache lock |  0.000023 |
| Sending data                 | 23.339035 |
| end                          |  0.000807 |
| query end                    |  0.000023 |
| closing tables               |  0.000325 |
| freeing items                |  0.001217 |
| logging slow query           |  0.000007 |
| logging slow query           |  0.000011 |
| cleaning up                  |  0.000104 |
+------------------------------+-----------+
100 rows in set (0.00 sec)

टेबल्स संरचनाएं:

CREATE TABLE `attribute` (
  `attribute_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `attribute_type_id` int(11) unsigned DEFAULT NULL,
  `attribute_value` int(6) DEFAULT NULL,
  `person_id` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`attribute_id`),
  KEY `attribute_type_id` (`attribute_type_id`),
  KEY `attribute_value` (`attribute_value`),
  KEY `person_id` (`person_id`)
) ENGINE=MyISAM AUTO_INCREMENT=40000001 DEFAULT CHARSET=utf8;

CREATE TABLE `person` (
  `person_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `person_name` text CHARACTER SET latin1,
  PRIMARY KEY (`person_id`)
) ENGINE=MyISAM AUTO_INCREMENT=20000001 DEFAULT CHARSET=utf8;

SSD और 1GB RAM के साथ DigitalOean वर्चुअल सर्वर पर क्वेरी की गई थी।

मुझे लगता है कि डेटाबेस डिजाइन में समस्या हो सकती है। क्या आपके पास इस स्थिति को बेहतर तरीके से डिजाइन करने के लिए कोई सुझाव है? या सिर्फ ऊपर का चयन समायोजित करने के लिए?


4
वह मूल्य है जो आप ईएवी डिजाइन के लिए भुगतान करते हैं। आप पर एक समग्र सूचकांक करके देख सकते हैंattribute (person_id, attribute_type_id, attribute_value)
mustaccio

1
मैं इन अनुक्रमों को जोड़ने की कोशिश करूँगा: (attribute_type_id, attribute_value, person_id)और (attribute_type_id, person_id, attribute_value)
ypercube

5
और InnoDB का उपयोग करें, MyISAM को फेंक दें। यह 2015 है, MyiSAM लंबे समय से मृत है।
ypercube y

2
पहली बात - LEFT जॉइन से छुटकारा पाएं, इसका कोई प्रभाव नहीं पड़ता है क्योंकि आप अपनी WHERE की स्थिति में सभी तालिकाओं का उपयोग करते हैं, प्रभावी रूप से INNER के सभी जॉइन को जोड़ते हैं (ऑप्टिमाइज़र को इसे समझने और अनुकूलन करने में सक्षम होना चाहिए लेकिन इसे कठिन बनाने के लिए बेहतर नहीं है। )। दूसरी बात - क्वेरी कैश को तब तक अक्षम करें जब तक आपके पास इसका उपयोग करने का एक मजबूत कारण न हो (= आपने इसका परीक्षण किया और मापा कि यह आपकी मदद करता है)
jkavalik

2
OT: क्या यह अजीब नहीं है कि आप ORDER BY की सीमा का उपयोग करें? यह कुछ यादृच्छिक 100000 पंक्तियाँ लौटाएगा?
ibre5041

जवाबों:


8

में शामिल करने के लिए कुछ विशेषताओं को चुनें person। उन्हें कुछ संयोजनों में अनुक्रमित करें - संयुक्त अनुक्रमणिका का उपयोग करें, एकल-स्तंभ अनुक्रमणिका नहीं।

यह मूल रूप से EAV-sucks-at-performance से बाहर निकलने का एकमात्र तरीका है, जो आप हैं।

यहां अधिक चर्चा है: http://mysql.rjweb.org/doc.php/eav जिसमें कुंजी मूल्य तालिका के बजाय JSON का उपयोग करने का सुझाव शामिल है।


3

इसके attributeलिए इंडोल जोड़ें :

  • (person_id, attribute_type_id, attribute_value) तथा
  • (attribute_type_id, attribute_value, person_id)

व्याख्या

अपने वर्तमान डिज़ाइन के साथ पंक्तियों की EXPLAINजांच करने के लिए आपकी क्वेरी की अपेक्षा करता 1,265,229 * 4 * 4 * 4 = 80,974,656है attribute। आप एक जोड़कर इस संख्या को कम कर सकते हैं समग्र सूचकांक पर attributeके लिए (person_id, attribute_type_id)। इस अनुक्रमणिका का उपयोग करके आपकी क्वेरी प्रत्येक के लिए 4 पंक्तियों के बजाय केवल 1 की जांच करेगी location, eyecolorऔर gender

आपको लगता है कि सूचकांक का विस्तार शामिल करने के लिए कर सकता है attribute_type_valueके रूप में अच्छी तरह से: (person_id, attribute_type_id, attribute_value)। यह इस क्वेरी के लिए इस इंडेक्स को कवरिंग इंडेक्स में बदल देगा , जिससे प्रदर्शन में भी सुधार होना चाहिए।

इसके अलावा (attribute_type_id, attribute_value, person_id)(फिर एक कवर इंडेक्स को शामिल करके person_id) एक इंडेक्स को जोड़ने पर केवल एक इंडेक्स का उपयोग करके प्रदर्शन को बेहतर करना चाहिए attribute_valueजहां अधिक पंक्तियों की जांच करनी होगी। इस मामले में यह आपके स्पष्टीकरण में पहला कदम तेज करेगा: से एक सीमा का चयन करना bornyear

उन दो इंडोल का उपयोग करके मेरी क्वेरी के निष्पादन समय को मेरे सिस्टम पर ~ 2.0 s से ~ 0.2 s तक कम कर दिया, जैसे कि आउटपुट आउटपुट इस तरह दिख रहा है:

+----+-------------+----------+--------+-------------------------------------+-------------------+---------+--------------------------------+---------+----------+--------------------------+
| id | select_type | table    | type   | possible_keys                       | key               | key_len | ref                            |    rows | filtered | Extra                    |
+----+-------------+----------+--------+-------------------------------------+-------------------+---------+--------------------------------+---------+----------+--------------------------+
|  1 | SIMPLE      | bornyear | range  | person_type_value,type_value_person | type_value_person |       9 |                                | 1861881 |   100.00 | Using where; Using index |
|  1 | SIMPLE      | location | ref    | person_type_value,type_value_person | person_type_value |       8 | bornyear.person_id,const       |       1 |   100.00 | Using where; Using index |
|  1 | SIMPLE      | eyecolor | ref    | person_type_value,type_value_person | person_type_value |       8 | bornyear.person_id,const       |       1 |   100.00 | Using where; Using index |
|  1 | SIMPLE      | gender   | ref    | person_type_value,type_value_person | person_type_value |      13 | bornyear.person_id,const,const |       1 |   100.00 | Using index              |
|  1 | SIMPLE      | person   | eq_ref | PRIMARY                             | PRIMARY           |       4 | bornyear.person_id             |       1 |   100.00 | Using index              |
+----+-------------+----------+--------+-------------------------------------+-------------------+---------+--------------------------------+---------+----------+--------------------------+

1
व्यापक उत्तर और स्पष्टीकरण के लिए धन्यवाद। मैंने आप सभी का उल्लेख किया था, लेकिन क्वेरी अभी भी ~ 2 मिनट लगती है। कृपया, आप किस तालिका प्रकार (निर्दोष, मायसम) का उपयोग कर रहे हैं और किस सटीक क्वेरी का प्रदर्शन किया है?
मार्टिन

1
इंडोल जोड़ने के अलावा मैंने आपके द्वारा किए गए सटीक डेटा और परिभाषाओं का उपयोग किया, इसलिए मैंने MyISAM का उपयोग किया। मैंने आपकी क्वेरी की पहली पंक्ति बदल दी SELECT person.person_idक्योंकि अन्यथा यह स्पष्ट रूप से नहीं चलेगी। आपने ANALYZE TABLE attributeइंडोल जोड़ने के बाद क्या किया ? आप EXPLAINअपने प्रश्न के साथ अपने नए आउटपुट (इंडोल जोड़ने के बाद) को भी जोड़ना चाह सकते हैं ।
wolfgangwalther

3

मुझे लगता है कि डेटाबेस डिजाइन में समस्या हो सकती है।

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

क्या आपके पास इस स्थिति को बेहतर तरीके से डिजाइन करने के लिए कोई सुझाव है?

इसे डिजाइन करने के लिए क्लासिक संबंधपरक तरीका प्रत्येक विशेषता के लिए एक अलग तालिका बना रहा है। सामान्य तौर पर, आप इन अलग-अलग तालिकाओं हो सकता है: location, gender, bornyear, eyecolor

निम्नलिखित इस बात पर निर्भर करता है कि किसी व्यक्ति के लिए कुछ विशेषताएं हमेशा परिभाषित की जाती हैं या नहीं। और, क्या किसी व्यक्ति के पास एक विशेषता का केवल एक मूल्य हो सकता है। उदाहरण के लिए, आमतौर पर व्यक्ति के पास केवल एक लिंग होता है। आपके वर्तमान डिज़ाइन में आपको एक ही व्यक्ति के लिए तीन पंक्तियों को जोड़ने से कुछ भी नहीं रोकता है, जिसमें लिंग के लिए अलग-अलग मान हैं। आप एक लिंग मान को 1 या 2 पर भी सेट कर सकते हैं, लेकिन कुछ संख्या जो समझ में नहीं आती है, जैसे 987 और डेटाबेस में कोई बाधा नहीं है जो इसे रोकती है। लेकिन, यह ईएवी डिज़ाइन के साथ डेटा अखंडता बनाए रखने का एक और अलग मुद्दा है।

आप हमेशा व्यक्ति के लिंग पता है, तो यह थोड़ा समझ में आता है एक अलग तालिका में यह डाल करने के लिए और यह एक गैर-शून्य स्तंभ के लिए जिस तरह से बेहतर है GenderIDमें personमेज, जो की सूची के साथ लुकअप तालिका के लिए एक विदेशी कुंजी होगा सभी संभव लिंग और उनके नाम। यदि आप उस व्यक्ति के लिंग को सबसे अधिक बार जानते हैं, लेकिन हमेशा नहीं, तो आप इस कॉलम को अशक्त बना सकते हैं और NULLजानकारी उपलब्ध नहीं होने पर इसे सेट कर सकते हैं । यदि अधिकांश समय व्यक्ति के लिंग का पता नहीं चलता है, तो एक अलग टेबल रखना बेहतर हो सकता है genderजो person1: 1 से लिंक करता है और इसमें केवल उन लोगों के लिए पंक्तियाँ होती हैं जिनके पास एक ज्ञात लिंग होता है।

इसी प्रकार के विचार के लिए लागू eyecolorऔर bornyear- व्यक्ति को एक के लिए दो मानों की संभावना नहीं है eyecolorया bornyear

यदि किसी विशेषता के लिए किसी व्यक्ति के लिए कई मान होना संभव है, तो आप निश्चित रूप से इसे एक अलग तालिका में डालेंगे। उदाहरण के लिए, किसी व्यक्ति के लिए कई पते (घर, काम, डाक, छुट्टी, आदि) होना असामान्य नहीं है, इसलिए आप उन सभी को एक तालिका में सूचीबद्ध करेंगे location। टेबल्स personऔर locationलिंक किए जाएंगे 1: एम।


या सिर्फ ऊपर का चयन समायोजित करने के लिए?

यदि ईएवी डिज़ाइन का उपयोग कर रहे हैं, तो मैं कम से कम निम्नलिखित काम करूंगा।

  • कॉलम सेट करें attribute_type_id, को attribute_value, person_idको NOT NULL
  • लिंक के attribute.person_idसाथ विदेशी कुंजी सेट करें person.person_id
  • तीन कॉलम पर एक इंडेक्स बनाएं (attribute_type_id, attribute_value, person_id)। स्तंभों का क्रम यहाँ महत्वपूर्ण है।
  • जहाँ तक मुझे पता है, MyISAM विदेशी कुंजियों का सम्मान नहीं करता है, इसलिए इसका उपयोग न करें, इसके बजाय InnoDB का उपयोग करें।

मैं इस तरह क्वेरी लिखूंगा। इंडेक्स का उपयोग करने के लिए सभी विकल्पों को ऑप्टिमाइज़र देने के लिए प्रत्येक विशेषता के लिए जॉइन के INNERबजाय उपयोग करें LEFTऔर स्पष्ट रूप से सबक्वेरी लिखें।

SELECT person.person_id
FROM
    person
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 1
            AND location.attribute_value BETWEEN 3000 AND 7000
    ) AS location ON location.person_id = person.person_id
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 2
            AND location.attribute_value = 1
    ) AS gender ON gender.person_id = person.person_id
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 3
            AND location.attribute_value BETWEEN 1980 AND 2000
    ) AS bornyear ON bornyear.person_id = person.person_id
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 4
            AND location.attribute_value IN (2, 3)
    ) AS eyecolor ON eyecolor.person_id = person.person_id
LIMIT 100000;

इसके अलावा, यह तालिका के विभाजन के लायक हो सकता attributeहै attribute_type_id


प्रदर्शन सावधानी: JOIN ( SELECT ... )अच्छी तरह से अनुकूलन नहीं करता है। JOINingसीधे टेबल बेहतर काम करता है (लेकिन अभी भी समस्याग्रस्त है)।
रिक जेम्स

3

मुझे आशा है कि मुझे एक पर्याप्त समाधान मिल गया है। यह इस लेख से प्रेरित है ।

संक्षिप्त जवाब:

  1. मैंने सभी विशेषताओं के साथ 1 तालिका बनाई है। एक विशेषता के लिए एक कॉलम। प्लस प्राथमिक कुंजी स्तंभ।
  2. विशेषता मान CSV जैसे प्रारूप में पाठ कोशिकाओं (पूर्ण-पाठ खोज के लिए) में संग्रहीत हैं।
  3. पूर्ण-पाठ अनुक्रमित बनाया गया। इससे पहले कि यह ft_min_word_len=1(MyISAM के लिए) [mysqld]अनुभाग में और innodb_ft_min_token_size=1(InnoDb के लिए) my.cnfफ़ाइल में सेट करना महत्वपूर्ण है , mysql सेवा को पुनरारंभ करें।
  4. खोज करने का उदाहरण: SELECT * FROM person_index WHERE MATCH(attribute_1) AGAINST("123 456 789" IN BOOLEAN MODE) LIMIT 1000जहां 123, 456एक 789आईडी है जो व्यक्तियों को संबंधित होना चाहिए attribute_1। इस क्वेरी को 1 सेकंड के अंतर्गत लिया गया।

विस्तृत जवाब:

चरण 1. फुलटेक्स इंडेक्स के साथ तालिका बनाना। InnoDb MySQL 5.7 से फुलटेक्स्ट इंडेक्स का समर्थन करता है इसलिए यदि आप 5.5 या 5.6 का उपयोग करते हैं, तो आपको MyISAM का उपयोग करना चाहिए। यह कभी-कभी FT से InnoDb की तुलना में भी तेज़ होता है।

CREATE TABLE `person_attribute_ft` (
  `person_id` int(11) NOT NULL,
  `attr_1` text,
  `attr_2` text,
  `attr_3` text,
  `attr_4` text,
  PRIMARY KEY (`person_id`),
  FULLTEXT KEY `attr_1` (`attr_1`),
  FULLTEXT KEY `attr_2` (`attr_2`),
  FULLTEXT KEY `attr_3` (`attr_3`),
  FULLTEXT KEY `attr_4` (`attr_4`),
  FULLTEXT KEY `attr_12` (`attr_1`,`attr_2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

चरण 2. ईएवी (इकाई-विशेषता-मूल्य) तालिका से डेटा डालें। उदाहरण के लिए प्रश्न में कहा गया है कि यह 1 सरल एसक्यूएल के साथ किया जा सकता है:

INSERT IGNORE INTO `person_attribute_ft`
SELECT
    p.person_id,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 1 AND a.person_id = p.person_id LIMIT 10) attr_1,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 2 AND a.person_id = p.person_id LIMIT 10) attr_2,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 3 AND a.person_id = p.person_id LIMIT 10) attr_3,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 4 AND a.person_id = p.person_id LIMIT 10) attr_4
FROM person p

परिणाम कुछ इस तरह होना चाहिए:

mysql> select * from person_attribute_ft limit 10;
+-----------+--------+--------+--------+--------+
| person_id | attr_1 | attr_2 | attr_3 | attr_4 |
+-----------+--------+--------+--------+--------+
|         1 | 541    | 2      | 1927   | 3      |
|         2 | 2862   | 2      | 1939   | 4      |
|         3 | 6573   | 2      | 1904   | 2      |
|         4 | 2432   | 1      | 2005   | 2      |
|         5 | 2208   | 1      | 1995   | 4      |
|         6 | 8388   | 2      | 1973   | 1      |
|         7 | 107    | 2      | 1909   | 4      |
|         8 | 5161   | 1      | 2005   | 1      |
|         9 | 8022   | 2      | 1953   | 4      |
|        10 | 4801   | 2      | 1900   | 3      |
+-----------+--------+--------+--------+--------+
10 rows in set (0.00 sec)

चरण 3. इस तरह क्वेरी के साथ तालिका से चयन करें:

mysql> SELECT SQL_NO_CACHE *
    -> FROM `person_attribute_ft`
    -> WHERE 1 AND MATCH(attr_1) AGAINST ("3000 3001 3002 3003 3004 3005 3006 3007" IN BOOLEAN MODE)
    -> AND MATCH(attr_2) AGAINST ("1" IN BOOLEAN MODE)
    -> AND MATCH(attr_3) AGAINST ("1980 1981 1982 1983 1984" IN BOOLEAN MODE)
    -> AND MATCH(attr_4) AGAINST ("2,3" IN BOOLEAN MODE)
    -> LIMIT 10000;
+-----------+--------+--------+--------+--------+
| person_id | attr_1 | attr_2 | attr_3 | attr_4 |
+-----------+--------+--------+--------+--------+
|     12131 | 3002   | 1      | 1982   | 2      |
|     51315 | 3007   | 1      | 1984   | 2      |
|    147283 | 3001   | 1      | 1984   | 2      |
|    350086 | 3005   | 1      | 1982   | 3      |
|    423907 | 3004   | 1      | 1982   | 3      |
... many rows ...
|   9423907 | 3004   | 1      | 1982   | 3      |
|   9461892 | 3007   | 1      | 1982   | 2      |
|   9516361 | 3006   | 1      | 1980   | 2      |
|   9813933 | 3005   | 1      | 1982   | 2      |
|   9986892 | 3003   | 1      | 1981   | 2      |
+-----------+--------+--------+--------+--------+
90 rows in set (0.17 sec)

क्वेरी सभी पंक्तियों का चयन करती है:

  • इनमें से कम से कम एक आईडी से मिलान करना attr_1:3000, 3001, 3002, 3003, 3004, 3005, 3006 or 3007
  • और उसी समय मिलान 1में attr_2(यह कॉलम लिंग का प्रतिनिधित्व करता है इसलिए यदि यह समाधान अनुकूलित किया गया था, तो यह smallint(1)सरल सूचकांक, आदि के साथ होना चाहिए ...)
  • और कम से कम एक में एक ही समय मिलान में 1980, 1981, 1982, 1983 or 1984मेंattr_3
  • और एक ही समय में मिलान 2या 3मेंattr_4

निष्कर्ष:

मुझे पता है कि यह समाधान कई स्थितियों के लिए सही और आदर्श नहीं है, लेकिन ईएवी टेबल डिजाइन के लिए अच्छे विकल्प के रूप में इस्तेमाल किया जा सकता है।

मुझे आशा है कि यह किसी की मदद करेगा।


1
मुझे यह बहुत कम संभावना लगता है कि यह डिजाइन आपके मूल डिजाइन से बेहतर समग्र अनुक्रमणिका के साथ प्रदर्शन करेगा। उनकी तुलना करने के लिए आपने क्या परीक्षण किए?
ypercube y

0

क्वेरी इंडेक्स संकेत का उपयोग करने की कोशिश करें जो उचित लगे

मयस्कल सूचकांक संकेत


1
संकेत क्वेरी के एक संस्करण की मदद कर सकते हैं, लेकिन फिर दूसरे को चोट पहुँचा सकते हैं। ध्यान दें कि ऑप्टिमाइज़र ने पहले सबसे अच्छे टेबल के रूप में जन्म लिया, शायद इसलिए कि सबसे अवांछनीय पंक्तियों को फ़िल्टर किया गया हो।
रिक जेम्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.