クエリのEXPLAIN
プランを見て、どこで最適化を行うのが最適かをどのように判断しますか?
最初に確認すべきことの 1 つは、適切なインデックスが使用されているかどうかということですが、それ以上は少し困惑しています。過去の試行錯誤の結果、結合が実行される順序が改善の良いソースになり得ることが時々わかりましたが、実行計画を見てそれをどのように判断できますか?
クエリを最適化する方法についての一般的な理解を深めたいと思っていますが (読んでいただければ幸いです!)、抽象的に話すよりも具体的なケースについて話し合う方が簡単であることもわかっています。私は現在これで頭を壁にぶつけているので、あなたの考えは大歓迎です:
id select_type テーブル タイプ possible_keys キー key_len ref 行 エクストラ 1 SIMPLE S const PRIMARY,l,p,f4 PRIMARY 2 const 1 一時的な使用 1 SIMPLE Q ref PRIMARY,SS 2 const 204 インデックスの使用 1 SIMPLE V ref PRIMARY,n,QQ 5 const,db.Q.QID 6 where の使用; インデックスの使用; 明確 1 SIMPLE R1 ref PRIMARY,LL 154 const,db.V.VID 447 インデックスの使用。明確 1 SIMPLE W eq_ref PRIMARY,w PRIMARY 5 const,db.R.RID,const 1 where を使用。明確 1 SIMPLE R2 eq_ref PRIMARY,L PRIMARY 156 const,db.W.RID,const 1 where の使用; 明確
実行計画の最後の行を次のように解釈するのは正しいですか。
- 主キーが完全に一致するため、
R2
出力行ごとにフェッチする必要があるのは 1 行のみです。 R2
ただし、そのような出力行は、 ?に適用されるいくつかの基準に基づいてフィルタリングされます。
もしそうなら、私の問題はその最終ステップで発生するフィルタリングにあります。条件の結果がフィルタリングされない場合 (例: WHERE `Col_1_to_3` IN (1,2,3)
)、クエリは非常に高速に実行されます (~50ms)。ただし、条件によって選択された行が制限されている場合 ( WHERE `Col_1_to_3` IN (1,2)
)、クエリの所要時間はかなり長くなります (最大 5 秒)。制限が単一の一致 ( WHERE `Col_1_to_3` IN (1)
) にある場合、オプティマイザはまったく異なる実行計画を提案します (5 秒よりわずかに優れていますが、それでも 50 ミリ秒よりはるかに悪い)。そのテーブルで使用できるより良いインデックスがあるようには見えません (結果ごとに 1 つの行を返すために既に主キーを完全に使用していることを考えると?)。
このすべての情報をどのように解釈すべきでしょうか? このような出力フィルタリングは結合される最終テーブルで行われるため、以前にテーブルに結合してそのような行をより早くフィルタリングするのに比べて、かなりの労力が無駄になっていると推測できますか? R2
もしそうなら、実行計画のいつ参加すべきかをどのように判断しますか?
ここにクエリとスキーマを完全に含めることには抵抗しましたが (単に答えを言われるだけでなく、何を探すべきかを知っている可能性が非常に高いため)、議論を進める必要があることは理解しています。
SELECT DISTINCT
`Q`.`QID`
FROM
`S`
NATURAL JOIN `Q`
NATURAL JOIN `V`
NATURAL JOIN `R` AS `R1`
NATURAL JOIN `W`
JOIN `R` AS `R2` ON (
`R2`.`SID` = `S`.`SID`
AND `R2`.`RID` = `R1`.`RID`
AND `R2`.`VID` = `S`.`V_id`
AND `R2`.`Col_1_to_3` IN (1,2) -- this is where performance suffers!
)
WHERE
AND `S`.`SID` = @x
AND `W`.`WID` = @y
;
テーブルの定義は次のとおりR
です。
CREATE TABLE `R` (
`SID` smallint(6) unsigned NOT NULL,
`RID` smallint(6) unsigned NOT NULL,
`VID` varchar(50) NOT NULL DEFAULT '',
`Col_1_to_3` smallint(1) DEFAULT NULL,
`T` varchar(255) DEFAULT NULL,
PRIMARY KEY (`SID`,`RID`,`VID`),
KEY `L` (`SID`,`VID`,`Col_1_to_3`),
CONSTRAINT `R_f1` FOREIGN KEY (`SID`) REFERENCES `S` (`SID`),
CONSTRAINT `R_f2` FOREIGN KEY (`SID`, `VID`) REFERENCES `V` (`SID`, `VID`),
CONSTRAINT `R_f3` FOREIGN KEY (`SID`, `VID`, `Col_1_to_3`) REFERENCES `L` (`SID`, `VID`, `LID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8