我有以下查询
select * from mapping_channel_fqdn_virtual_host where id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
解释上面的查询给出了以下结果:
explain select * from mapping_channel_fqdn_virtual_host where id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+----+-------------+-----------------------------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------------------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | SIMPLE | mapping_channel_fqdn_virtual_host | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 10 | 100.00 | Using where |
+----+-------------+-----------------------------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0,00 sec)
id 是表的主键。看起来这是一种范围类型的查询,它使用主键作为该查询的索引。
当我尝试解释以下查询时,我得到不同的结果:
explain select * from mapping_channel_fqdn_virtual_host where id in (select max(id) from mapping_channel_fqdn_virtual_host group by channel_id, fqdn_virtual_host_id);
+----+-------------+-----------------------------------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------------------------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+
| 1 | PRIMARY | mapping_channel_fqdn_virtual_host | NULL | ALL | NULL | NULL | NULL | NULL | 4849 | 100.00 | Using where |
| 2 | SUBQUERY | mapping_channel_fqdn_virtual_host | NULL | index | idx_channel_fqdn | idx_channel_fqdn | 8 | NULL | 4849 | 100.00 | Using index |
+----+-------------+-----------------------------------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0,00 sec)
idx_channel_fqdn
是 groupby 子句中使用的列对的复合索引键。但是,当使用子查询时,主查询会像以前一样停止使用索引。您能解释一下为什么会发生这种情况吗?
尝试了 Anouar 建议的 JOIN 查询:
explain select * from mapping_channel_fqdn_virtual_host as x join (select max(id) as ids from mapping_channel_fqdn_virtual_host group by channel_id, fqdn_virtual_host_id) as y on x.id=y.ids;
+----+-------------+-----------------------------------+------------+--------+------------------+------------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------------------------+------------+--------+------------------+------------------+---------+-------+------+----------+-------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 4849 | 100.00 | Using where |
| 1 | PRIMARY | x | NULL | eq_ref | PRIMARY | PRIMARY | 4 | y.ids | 1 | 100.00 | NULL |
| 2 | DERIVED | mapping_channel_fqdn_virtual_host | NULL | index | idx_channel_fqdn | idx_channel_fqdn | 8 | NULL | 4849 | 100.00 | Using index |
+----+-------------+-----------------------------------+------------+--------+------------------+------------------+---------+-------+------+----------+-------------+
3 rows in set, 1 warning (0,00 sec)
从索引和 eq_ref 类型来看,看起来使用 JOIN 比使用子查询更好?您能多解释一下连接解释表达式的结果吗?
最佳答案
您可以看到the answers for this question 你会有很好的想法。
我引用了一些答案
Sometimes MySQL does not use an index, even if one is available. One circumstance under which this occurs is when the optimizer estimates that using the index would require MySQL to access a very large percentage of the rows in the table. (In this case, a table scan is likely to be much faster because it requires fewer seeks.)
简单地说,尝试强制索引:
SELECT *
FROM mapping_channel_fqdn_virtual_host FORCE INDEX (name of the index you want to use)
WHERE (mapping_channel_fqdn_virtual_host.id IN (1,2,3,4,5,6,7,8,9,10));
或者使用 JOIN 代替并查看解释
SELECT * FROM mapping_channel_fqdn_virtual_host mcf
JOIN (select max(id) as ids from mapping_channel_fqdn_virtual_host group by channel_id, fqdn_virtual_host_id)) AS mcfv
ON mcf.id = mcfv.ids;
关于mysql - 将 IN 与子查询一起使用不使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47097508/