MySQL:在 WHERE IN 子句中使用复合键的查询非常慢
MySQL: very slow query using composite key in WHERE IN clause
我有一个 MySQL table 和一个复合主键:(id1, id2)。我想获取 (id1, id2) 在成对列表中的所有行,例如((1,2),(2,6),(1,6))。当这个 pairs 列表只包含一个元素时,似乎使用了索引,因为查询速度非常快。当 pairs 的列表包含多个元素时,查询速度极慢:
mysql> SELECT id1, id2 FROM my_table WHERE (id1, id2) in ((1817279, 0));
+---------+--------+
| id1 | id2 |
+---------+--------+
| 1817279 | 0 |
+---------+--------+
1 row in set (0.00 sec)
mysql> SELECT id1, id2 FROM my_table WHERE (id1, id2) in ((1819781, 2));
+---------+--------+
| id1 | id2 |
+---------+--------+
| 1819781 | 2 |
+---------+--------+
1 row in set (0.00 sec)
mysql> SELECT id1, id2 FROM my_table WHERE (id1, id2) in ((1817279, 0), (1819781, 2));
+---------+--------+
| id1 | id2 |
+---------+--------+
| 1817279 | 0 |
| 1819781 | 2 |
+---------+--------+
2 rows in set (1 min 22.72 sec)
我尝试使用 FORCE INDEX (PRIMARY)
但没有成功。知道为什么 MySQL 无法使用索引吗?
这是我的 MySQL 版本:mysql Ver 14.14 Distrib 5.6.33, for debian-linux-gnu (x86_64) using EditLine wrapper
“行构造函数”直到 5.7.3 才得到优化。示例 WHERE (id1, id2) = (11, 22)
。来自变更日志:2013-12-03 5.7.3
Milestone 13 -- Functionality Added or Changed:
The optimizer now is able to apply the range scan access method to
queries of this form:
SELECT ... FROM t1 WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd'
));
Previously, for range scans to be used it was necessary for the query
to be written as:
SELECT ... FROM t1 WHERE ( col_1 = 'a' AND col_2 = 'b' ) OR ( col_1 =
'c' AND col_2 = 'd' );
For the optimizer to use a range scan, queries must satisfy these
conditions:
Only IN predicates can be used, not NOT IN.
There may only be column references in the row constructor on the IN predicate's left hand side.
There must be more than one row constructor on the IN predicate's right hand side.
Row constructors on the IN predicate's right hand side must contain only runtime constants, which are either literals or local
column references that are bound to constants during execution.
EXPLAIN output for applicable queries will change from full table or
index scan to range scan. Changes are also visible by checking the
values of the
Handler_read_first,
Handler_read_key,
and
Handler_read_next
status variables.
我有一个 MySQL table 和一个复合主键:(id1, id2)。我想获取 (id1, id2) 在成对列表中的所有行,例如((1,2),(2,6),(1,6))。当这个 pairs 列表只包含一个元素时,似乎使用了索引,因为查询速度非常快。当 pairs 的列表包含多个元素时,查询速度极慢:
mysql> SELECT id1, id2 FROM my_table WHERE (id1, id2) in ((1817279, 0));
+---------+--------+
| id1 | id2 |
+---------+--------+
| 1817279 | 0 |
+---------+--------+
1 row in set (0.00 sec)
mysql> SELECT id1, id2 FROM my_table WHERE (id1, id2) in ((1819781, 2));
+---------+--------+
| id1 | id2 |
+---------+--------+
| 1819781 | 2 |
+---------+--------+
1 row in set (0.00 sec)
mysql> SELECT id1, id2 FROM my_table WHERE (id1, id2) in ((1817279, 0), (1819781, 2));
+---------+--------+
| id1 | id2 |
+---------+--------+
| 1817279 | 0 |
| 1819781 | 2 |
+---------+--------+
2 rows in set (1 min 22.72 sec)
我尝试使用 FORCE INDEX (PRIMARY)
但没有成功。知道为什么 MySQL 无法使用索引吗?
这是我的 MySQL 版本:mysql Ver 14.14 Distrib 5.6.33, for debian-linux-gnu (x86_64) using EditLine wrapper
“行构造函数”直到 5.7.3 才得到优化。示例 WHERE (id1, id2) = (11, 22)
。来自变更日志:2013-12-03 5.7.3
Milestone 13 -- Functionality Added or Changed:
The optimizer now is able to apply the range scan access method to queries of this form:
SELECT ... FROM t1 WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd' ));
Previously, for range scans to be used it was necessary for the query to be written as:
SELECT ... FROM t1 WHERE ( col_1 = 'a' AND col_2 = 'b' ) OR ( col_1 = 'c' AND col_2 = 'd' );
For the optimizer to use a range scan, queries must satisfy these conditions:
Only IN predicates can be used, not NOT IN.
There may only be column references in the row constructor on the IN predicate's left hand side.
There must be more than one row constructor on the IN predicate's right hand side.
Row constructors on the IN predicate's right hand side must contain only runtime constants, which are either literals or local column references that are bound to constants during execution.
EXPLAIN output for applicable queries will change from full table or index scan to range scan. Changes are also visible by checking the values of the Handler_read_first, Handler_read_key, and Handler_read_next status variables.