Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

एक IN स्थिति sql में =से धीमी क्यों होगी?

सारांश:यह एक ज्ञात समस्या है MySQL में और MySQL 5.6.x में तय किया गया था। समस्या अनुपलब्ध ऑप्टिमाइज़ेशन के कारण होती है जब IN का उपयोग करने वाली एक सबक्वेरी को एक स्वतंत्र सबक्वेरी के बजाय डिपेंडेंट सबक्वेरी के रूप में गलत तरीके से पहचाना जाता है।

जब आप मूल क्वेरी पर EXPLAIN चलाते हैं तो यह इसे लौटाता है:

1  'PRIMARY'             'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
2  'DEPENDENT SUBQUERY'  'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
3  'DEPENDENT SUBQUERY'  'question_law'          'ALL'  ''  ''  ''  ''  10040  'Using where'

जब आप IN बदलते हैं करने के लिए = आपको यह मिलता है:

1  'PRIMARY'   'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
2  'SUBQUERY'  'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
3  'SUBQUERY'  'question_law'          'ALL'  ''  ''  ''  ''  10040  'Using where'

प्रत्येक आश्रित सबक्वेरी को उस क्वेरी में प्रति पंक्ति एक बार चलाया जाता है, जिसमें वह समाहित है, जबकि सबक्वेरी केवल एक बार चलती है। MySQL कभी-कभी आश्रित उपश्रेणियों को अनुकूलित कर सकता है जब ऐसी स्थिति होती है जिसे एक जॉइन में परिवर्तित किया जा सकता है लेकिन यहाँ ऐसा नहीं है।

अब यह निश्चित रूप से इस सवाल को छोड़ देता है कि MySQL का मानना ​​​​है कि IN संस्करण को एक आश्रित उपश्रेणी की आवश्यकता क्यों है। मैंने इसकी जांच में सहायता के लिए क्वेरी का एक सरलीकृत संस्करण बनाया है। मैंने दो टेबल 'फू' और 'बार' बनाए, जहां पूर्व में केवल एक आईडी कॉलम होता है, और बाद वाले में एक आईडी और एक फू आईडी दोनों होते हैं (हालांकि मैंने एक विदेशी कुंजी बाधा नहीं बनाई है)। फिर मैंने दोनों टेबलों को 1000 पंक्तियों के साथ आबाद किया:

CREATE TABLE foo (id INT PRIMARY KEY NOT NULL);
CREATE TABLE bar (id INT PRIMARY KEY, foo_id INT NOT NULL);

-- populate tables with 1000 rows in each

SELECT id
FROM foo
WHERE id IN
(
    SELECT MAX(foo_id)
    FROM bar
);

इस सरलीकृत क्वेरी में पहले जैसी ही समस्या है - आंतरिक चयन को एक आश्रित सबक्वेरी के रूप में माना जाता है और कोई अनुकूलन नहीं किया जाता है, जिससे आंतरिक क्वेरी प्रति पंक्ति एक बार चलती है। क्वेरी को चलने में लगभग एक सेकंड का समय लगता है। IN को बदलना करने के लिए = फिर से क्वेरी को लगभग तुरंत चलने देता है।

यदि कोई व्यक्ति परिणामों को पुन:प्रस्तुत करना चाहता है, तो तालिका को पॉप्युलेट करने के लिए मैंने जिस कोड का उपयोग किया है, वह नीचे है।

CREATE TABLE filler (
        id INT NOT NULL PRIMARY KEY AUTO_INCREMENT
) ENGINE=Memory;

DELIMITER $$

CREATE PROCEDURE prc_filler(cnt INT)
BEGIN
        DECLARE _cnt INT;
        SET _cnt = 1;
        WHILE _cnt <= cnt DO
                INSERT
                INTO    filler
                SELECT  _cnt;
                SET _cnt = _cnt + 1;
        END WHILE;
END
$$

DELIMITER ;

CALL prc_filler(1000);

INSERT foo SELECT id FROM filler;
INSERT bar SELECT id, id FROM filler;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQLException:कोई उपयुक्त ड्राइवर नहीं मिला

  2. टर्मिनल के भीतर से mysql का उपयोग करके चेतावनी संदेशों को रोकें, लेकिन पासवर्ड बैश स्क्रिप्ट में लिखा गया है

  3. ETL प्रक्रिया में Python और MySQL का उपयोग करना

  4. मूल्यों की सूची में नहीं के लिए MySQL चर प्रारूप

  5. डेटाबेस स्केलिंग पैटर्न को समझने के लिए एक गाइड