2 億レコードのテーブル Foo と 1000 レコードのテーブル Bar があり、それらは多対 1 で接続されています。列 Foo.someTime および Bar.someField のインデックスがあります。また、Bar 900 レコードの someField は 1 で、100 レコードの someField は 2 です。
(1) このクエリはすぐに実行されます。
mysql> select * from Foo f inner join Bar b on f.table_id = b.table_id where f.someTime between '2008-08-14' and '2018-08-14' and b.someField = 1 limit 20;
...
20 rows in set (0.00 sec)
(2) これには永遠に時間がかかります (唯一の変更は b.someField = 2 です):
mysql> select * from Foo f inner join Bar b on f.table_id = b.table_id where f.someTime between '2008-08-14' and '2018-08-14' and b.someField = 2 limit 20;
(3) しかし、someTime の where 句を削除すると、すぐに実行されます。
mysql> select * from Foo f inner join Bar b on f.table_id = b.table_id where b.someField = 2 limit 20;
...
20 rows in set (0.00 sec)
(4) また、インデックスの使用を強制することで高速化できます。
mysql> select * from Foo f inner join Bar b force index(someField) on f.table_id = b.table_id where f.someTime between '2008-08-14' and '2018-08-14' and b.someField = 2 limit 20;
...
20 rows in set (0.00 sec)
これがクエリ(2)の説明です(永遠にかかります)
+----+-------------+-------+--------+-------------------------------+-----------+---------+--------------------------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------------------+-----------+---------+--------------------------+----------+-------------+
| 1 | SIMPLE | g | range | bar_id,bar_id_2,someTime | someTime | 4 | NULL | 95022220 | Using where |
| 1 | SIMPLE | t | eq_ref | PRIMARY,someField,bar_id | PRIMARY | 4 | db.f.bar_id | 1 | Using where |
+----+-------------+-------+--------+-------------------------------+-----------+---------+--------------------------+----------+-------------+
(4)の説明は次のとおりです(フォースインデックスがあります)
+----+-------------+-------+------+-------------------------------+-----------+---------+--------------------------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------------------+-----------+---------+--------------------------+----------+-------------+
| 1 | SIMPLE | t | ref | someField | someField | 1 | const | 92 | |
| 1 | SIMPLE | g | ref | bar_id,bar_id_2,someTime | bar_id | 4 | db.f.foo_id | 10558024 | Using where |
+----+-------------+-------+------+-------------------------------+-----------+---------+--------------------------+----------+-------------+
問題は、MySQL に正しいインデックスを使用するように教える方法です。クエリは ORM によって生成され、これら 2 つのフィールドだけに限定されません。また、クエリをあまり変更しないようにすることもお勧めします (ただし、内部結合がここに適合するかどうかはわかりません)。
アップデート:
mysql> create index index_name on Foo (bar_id, someTime);
その後、クエリ (2) は 0.00 秒で実行されます。