सारांश:यह एक ज्ञात समस्या है 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;