ファイルの並べ替えを回避するために、WHEREでIN句を使用するクエリを最適化しようとしています。簡単にするために、問題を示す次のサンプルを作成しました。これが私のクエリです:
SELECT *
FROM `test`
WHERE user_id = 9898
AND status IN (1,3,4)
order by id
limit 30;
クエリがfilesortであることがわかるように、これは説明の結果です
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test range user_id user_id 8 NULL 3 Using where; Using index; Using filesort
これが私のテーブル構造です
CREATE TABLE IF NOT EXISTS `test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`status` int(3) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
--
-- Dumping data for table `test`
--
INSERT INTO `test` (`id`, `user_id`, `status`) VALUES
(5, 9797, 2),
(6, 9797, 3),
(4, 9898, 0),
(1, 9898, 2),
(2, 9898, 3),
(3, 9898, 4);
クエリを最適化するにはどうすればよいですか?実際のテーブルでは、エラーログで次の情報を確認できます:# Query_time: 26.498180 Lock_time: 0.000175 Rows_sent: 100 Rows_examined: 4926
今日は非常に似た問題を見ていました。オンラインで大量の検索を行った後、私はこれを見つけました Perconaによる素晴らしい記事
「UNION ALL」を使用すると、次のようにクエリのリストを結合できます。
_(SELECT * FROM `test` WHERE user_id = 9898 AND status = 1 ORDER BY id LIMIT 30)
UNION ALL
(SELECT * FROM `test` WHERE user_id = 9898 AND status = 3 ORDER BY id LIMIT 30)
UNION ALL
(SELECT * FROM `test` WHERE user_id = 9898 AND status = 4 ORDER BY id LIMIT 30)
ORDER BY id LIMIT 30
_
looksselect ... status IN (1,3,4)
と比較すると危険ですが、ファイルソートを回避するのに効果的です。
内部の「SELECT ...」ステートメントが効率的である限り、パフォーマンスは良好です。
値のリストを一時テーブルに入れ、それに対して内部結合を実行します。ほとんどのSQLオプティマイザーとエンジンは、IN操作を処理するよりもはるかに優れて結合を処理できます。リストが長い場合、これにより、一時テーブルにインデックスを定義して、オプティマイザをさらに支援することもできます。