有人可以解释为什么这些查询之间存在很大差异吗?
所有这些结果完全相同。
query 1
的效果:非常好,query 2
:不好,query 3
:很好。
为什么query 2
从表test
(id 1)中选择包含所有行?为什么possible_keys
不包含实际使用的PRIMARY
?
表:
CREATE TABLE `test` (
`id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `test` ADD PRIMARY KEY (`id`);
数据:
DROP PROCEDURE IF EXISTS insert1000;
DELIMITER $$
CREATE PROCEDURE insert1000()
BEGIN
SET @i = 1;
WHILE @i < 1000 DO
INSERT INTO `test` VALUES (@i);
SET @i = @i + 1;
END WHILE;
END
$$
DELIMITER ;
CALL insert1000();
DROP PROCEDURE insert1000;
查询1:
SELECT `id` FROM `test` WHERE `id` IN (2, 3)
查询1解释:
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| 1 | SIMPLE | test | range | PRIMARY | PRIMARY | 4 | NULL | 2 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
查询2:
SELECT `id` FROM `test` WHERE `id` IN (SELECT 2 UNION SELECT 3)
查询2解释:
+------+--------------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+--------------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
| 1 | PRIMARY | test | index | NULL | PRIMARY | 4 | NULL | 999 | Using where; Using index |
+------+--------------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
| 2 | DEPENDENT SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+------+--------------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
| 3 | DEPENDENT UNION | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+------+--------------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
| NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | |
+------+--------------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
查询3:
SELECT `id` FROM `test` WHERE `id` IN (SELECT * FROM (SELECT 2 UNION SELECT 3) AS `derived`)
查询3解释:
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
| 1 | PRIMARY | <subquery2> | ALL | distinct_key | NULL | NULL | NULL | 2 | |
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
| 1 | PRIMARY | test | eq_ref | PRIMARY | PRIMARY | 4 | derived.2 | 1 | Using where; Using index |
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
| 2 | MATERIALIZED | <derived3> | ALL | NULL | NULL | NULL | NULL | 2 | |
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
| 3 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
| 4 | UNION | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
| NULL | UNION RESULT | <union3,4> | ALL | NULL | NULL | NULL | NULL | NULL | |
+------+--------------+-------------+--------+---------------+---------+---------+-----------+------+--------------------------+
答案 0 :(得分:1)
MySQL优化器的内部工作原理......
虽然query 2
和query 3
都需要全表扫描(无法使用索引),但它们的不同语法会使优化程序使用不同的策略。
通过运行EXPLAIN EXTENDED SELECT ...
然后运行SHOW WARNINGS;
,您可以更清楚地看到它。
这是query 2
的扩展计划:
select `test`.`id` AS `id`
from `test`
where <in_optimizer>(`test`.`id`,<exists>(select 2 having (<cache>(`test`.`id`) = <ref_null_helper>(2))
union
select 3 having (<cache>(`test`.`id`) = <ref_null_helper>(3))
))
优化程序会将IN
翻译为EXISTS
,然后将2个查询SELECT 2
和SELECT 3
的结果与test
中扫描的行进行比较。< / p>
这是query 3
的扩展计划:
select `test`.`id` AS `id`
from `test`
where <in_optimizer>(`test`.`id`,<exists>(select 1 from (select 2 AS `2` union select 3 AS `3`) `derived` where (<cache>(`test`.`id`) = `derived`.`2`)))
您可以看到,在这种情况下,优化器正在运行原始UNION
以创建值为2和3的派生表,然后将此表与它在表{{1}中扫描的数据进行一次比较}。