データが偏る #とは あるインデックスに紐づくレコードは均一に分散するとは限らない ex. SELECT COUNT(*) FROM 住民 WHERE 都道府県 = ? ‐ ある偏りについてオプティマイザが同じ実行計画を選ぶとは限らない ex. SELECT * FROM 住民 WHERE 都道府県 = '東京' ORDER BY birthday DESC LIMIT 10 万 vs. SELECT * FROM 住民 WHERE 都道府県 = '鳥取' ORDER BY birthday DESC LIMIT 10万 たぶん東京はORDER BYを狙った方が速くて、鳥取はWHEREを狙った方が速い(2020年の鳥取の人口は全国の0.4%らしい) 都道府県の人口一覧 - Wikipedia ‐ ex. SELECT * FROM 住民 WHERE 都道府県 = '東京' ORDER BY birthday DESC LIMIT 10 vs. SELECT * FROM 住民 WHERE 都道府県 = '東京' ORDER BY birthday DESC LIMIT 1億 LIMIT 1億だと日本総人口にかなり近いので全件フェッチの実行計画を選ぶが、LIMITの早抜けが効かないのでORDER BY狙いの キーは高速化に寄与できない ‐ だが、偏りに気が付かずにオプティマイザが実行計画を選んでしまうことはある 9/35
偏ったデータ対策 「あり得る最大の行」「あり得る最小の行」「あり得ない行」の3パターンでテストするとまあまあ検出 できるはず SELECT COUNT(*) FROM post WHERE user_id = ? AND registered BETWEEN ? AND ? + INTERVAL 1 MONTH; SELECT * FROM post WHERE user_id = ? AND registered BETWEEN ? AND ? + INTERVAL 1 MONTH O RDER BY registered LIMIT 100 FOR UPDATE; 16/35
ちょっと別口の偏り SELECT COUNT(*) FROM post WHERE user_id = ? AND registered BETWEEN ? AND ? + INTERVAL 1 MONTH; SELECT * FROM post WHERE user_id = ? AND registered BETWEEN ? AND ? + INTERVAL 1 MONTH O RDER BY registered LIMIT ? FOR UPDATE; DELETE FROM post WHERE post_id IN (?, ?, .., ?); 31/35