概要:これは既知の問題 です。 MySQLで、MySQL5.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'
依存する各サブクエリは、それが含まれるクエリの行ごとに1回実行されますが、サブクエリは1回だけ実行されます。 MySQLは、結合に変換できる条件がある場合に依存サブクエリを最適化できる場合がありますが、ここではそうではありません。
もちろん、これは、なぜMySQLがINバージョンが依存サブクエリである必要があると信じているのかという疑問を残します。これを調査するために、クエリの簡略化されたバージョンを作成しました。 2つのテーブル「foo」と「bar」を作成しました。前者にはid列のみが含まれ、後者にはidとfoo idの両方が含まれます(ただし、外部キー制約は作成しませんでした)。次に、両方のテーブルに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
);
この簡略化されたクエリには、以前と同じ問題があります。内部選択は依存サブクエリとして扱われ、最適化は実行されないため、内部クエリは行ごとに1回実行されます。クエリの実行には約1秒かかります。 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;