web-dev-qa-db-ja.com

whereクエリでwhereクエリのIN句を最適化する-MySQL

ファイルの並べ替えを回避するために、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

1
usef_ksa

今日は非常に似た問題を見ていました。オンラインで大量の検索を行った後、私はこれを見つけました 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 ...」ステートメントが効率的である限り、パフォーマンスは良好です。

1
Adam Easterling

値のリストを一時テーブルに入れ、それに対して内部結合を実行します。ほとんどのSQLオプティマイザーとエンジンは、IN操作を処理するよりもはるかに優れて結合を処理できます。リストが長い場合、これにより、一時テーブルにインデックスを定義して、オプティマイザをさらに支援することもできます。

1
Pieter Geerkens