Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

行値式の IN でインデックスが使われない

More than 5 years have passed since last update.

mysql 5.5.36、下記のような行値式を使ったクエリでインデックスが使われませんでした。
便利な構文ですが、使用するときは注意した方がいいかもしれません。

※ 2015/11/27 追記

mysql 5.7.9 で試したところ、インデックスが使われるようになっていました。

explain select * from tbl where (id, seq) in ((1, 100), (2, 200), (3, 300));
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | tbl   | NULL       | range | PRIMARY       | PRIMARY | 8       | NULL |    3 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

※ 追記ここまで

前提

CREATE TABLE `tbl` (
    `id` INT(11) NOT NULL,
    `seq` INT(11) NOT NULL,
    `data` TEXT NOT NULL,
    PRIMARY KEY (`id`, `seq`)
) ENGINE=InnoDB;

このようなテーブルで

+----+-----+-------+
| id | seq | data  |
+----+-----+-------+
|  1 | 100 | dummy |
|  2 | 200 | dummy |
|  3 | 300 | dummy |
+----+-----+-------+

このようなレコードを取得したいとします。
なお、レコードは 10000 行くらい突っ込んであります。

普通に OR で繋げた場合

explain select * from tbl where (id = 1 and seq = 100) or (id = 2 and seq = 200) or (id = 3 and seq = 300);
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | tbl   | range | PRIMARY       | PRIMARY | 8       | NULL |    3 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+

主キーが使用されています。

行値式の場合

explain select * from tbl where (id, seq) in ((1, 100), (2, 200), (3, 300));
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
|  1 | SIMPLE      | tbl   | ALL  | NULL          | NULL | NULL    | NULL | 10297 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+

全行読み込んでるっぽいです。
ちなみに IN を使わなければ使用されるようです。

explain select * from tbl where (id, seq) = (1, 100) or (id, seq) = (2, 200) or (id, seq) = (3, 300);
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | tbl   | range | PRIMARY       | PRIMARY | 8       | NULL |    3 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+

でもあんまり使ってるメリットを感じない…。

headjapan
中規模~大規模の安定した基幹システム・大規模サイトの分析・要件定義・設計・開発を得意とする、総合的な開発会社です。
http://www.headjapan.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away