insert into digit values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
CREATE VIEW numbers AS select a.a*1000 + b.a*100 + c.a*10 + d.a as n from digit a, digit b, digit c, digit d;
-- 本章中大部分案例都使用tab表 CREATE TABLE `tab` ( `id` int NOT NULL AUTO_INCREMENT, `a` int NOT NULL, `b` int NOT NULL, `c` int NOT NULL, `padding` varchar(7000) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_abc` (`a`,`b`,`c`) ) ENGINE=InnoDB;
insert into tab (a,b,c,padding) select n%3, n, n%100, rpad('x', 100, 'x') from numbers where n < 10000;
-- t_merge主要用于演示index_merge的几种情况 create table t_merge( id int not null auto_increment, a int not null, b int not null, c int not null, d int not null, padding varchar(4000), primary key(id), key idx_ad(a,d), key idx_bd(b,d), key idx_cd(c,d) ) ENGINE=InnoDB;
insert into t_merge(a,b,c,d,padding) select n % 3 + 1, n % 17 + 1, n % 19 + 1, n % 10 + 1, rpad('y', 100, 'y') from numbers where n between 1 and 3*17*19*10;
mysql> explain select /*+ NO_SEMIJOIN(@subq1 ) */ * from tab ta, tab tx where ta.id in ( select /*+ QB_NAME(subq1) NO_SEMIJOIN(@subq2) */ id from tab tb where c in (select /*+ QB_NAME(subq2) */ c from tab tc) ) and ta.id = tx.id
+----+-------------+-------+--------+---------------+---------+---------+-----------+------+----------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+--------+---------------+---------+---------+-----------+------+----------+--------------------------+ | 1 | PRIMARY | ta | ALL | PRIMARY | NULL | NULL | NULL | 9913 | 100.00 | Using where | | 1 | PRIMARY | tx | eq_ref | PRIMARY | PRIMARY | 4 | rep.ta.id | 1 | 100.00 | NULL | | 2 | SUBQUERY | tb | index | PRIMARY | idx_abc | 12 | NULL | 9913 | 100.00 | Using where; Using index | | 3 | SUBQUERY | tc | index | NULL | idx_abc | 12 | NULL | 9913 | 100.00 | Using index | +----+-------------+-------+--------+---------------+---------+---------+-----------+------+----------+--------------------------+
--这个例子在mariadb 10.0 中执行 mysql> explain extended select a, (select avg(b) from tab where a=t1.a) from tab t1; +------+--------------------+-------+-------+---------------+---------+---------+------------+------+----------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +------+--------------------+-------+-------+---------------+---------+---------+------------+------+----------+-------------+ | 1 | PRIMARY | t1 | index | NULL | idx_abc | 12 | NULL | 9919 | 100.00 | Using index | | 2 | DEPENDENT SUBQUERY | tab | ref | idx_abc | idx_abc | 4 | mysql.t1.a | 1668 | 100.00 | Using index | +------+--------------------+-------+-------+---------------+---------+---------+------------+------+----------+-------------+ 2 rows in set, 2 warnings (0.00 sec)
mysql> show warnings; +-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Note | 1276 | Field or reference 'mysql.t1.a' of SELECT #2 was resolved in SELECT #1 | | Note | 1003 | /* select#1 */ select `mysql`.`t1`.`a` AS `a`,<expr_cache><`mysql`.`t1`.`a`>((/* select#2 */ select avg(`mysql`.`tab`.`b`) from `mysql`.`tab` where `mysql`.`tab`.`a` = `mysql`.`t1`.`a`)) AS `(select avg(b) from tab where a=t1.a)` from `mysql`.`tab` `t1` | +-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
DERIVED
子查询出现在主查询的FROM子句的位置时,select_type为DERIVED。
1 2 3 4 5 6 7 8 9 10 11
mysql> explain select t1.* from tab t1, (select a, avg(b) as avgb from tab group by a) t2 where t1.a = t2.a; +----+-------------+------------+-------+---------------+-------------+---------+----------+------+----------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+-------+---------------+-------------+---------+----------+------+----------+-------------+ | 1 | PRIMARY | t1 | ALL | idx_abc | NULL | NULL | NULL | 9913 | 100.00 | NULL | | 1 | PRIMARY | <derived2> | ref | <auto_key0> | <auto_key0> | 4 | rep.t1.a | 10 | 100.00 | NULL | | 2 | DERIVED | tab | index | idx_abc | idx_abc | 12 | NULL | 9913 | 100.00 | Using index | +----+-------------+------------+-------+---------------+-------------+---------+----------+------+----------+-------------+
DEPENDENT DERIVED
如果派生查询引用了主查询中的字段,则select_type为DEPENDENT DERIVED。
1 2 3 4 5 6 7 8 9 10
mysql> explain select a, (select * from (select avg(b) as avgb from tab where a=t0.a) td) from tab t0;
mysql> explain select * from t_merge where (b=1 and d=1) or (c=1 and d between 3 and 5); +----+-------------+---------+-------------+---------------+---------------+---------+------+------+----------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+-------------+---------------+---------------+---------+------+------+----------+----------------------------------------------+ | 1 | SIMPLE | t_merge | index_merge | idx_bd,idx_cd | idx_bd,idx_cd | 8,8 | NULL | 210 | 100.00 | Using sort_union(idx_bd,idx_cd); Using where | +----+-------------+---------+-------------+---------------+---------------+---------+------+------+----------+----------------------------------------------+
mysql> explain select * from t_merge where a=1 and b=1 and d=1 and c=1; +----+-------------+---------+-------------+----------------------+----------------------+---------+------+------+----------+----------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+-------------+----------------------+----------------------+---------+------+------+----------+----------------------------------------------------+ | 1 | SIMPLE | t_merge | index_merge | idx_ad,idx_bd,idx_cd | idx_cd,idx_bd,idx_ad | 8,8,8 | NULL | 1 | 100.00 | Using intersect(idx_cd,idx_bd,idx_ad); Using where | +----+-------------+---------+-------------+----------------------+----------------------+---------+------+------+----------+----------------------------------------------------+
mysql> explain select /*+ NO_SEMIJOIN(@qb1) */ * from tab where a = 1 and b between 100 and 200 and c in (select /*+ QB_NAME(qb1) */ a from tab where b=1 );
+----+--------------------+-------+----------------+---------------+---------+---------+------------+------+----------+------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+--------------------+-------+----------------+---------------+---------+---------+------------+------+----------+------------------------------------+ | 1 | PRIMARY | tab | range | idx_abc | idx_abc | 8 | NULL | 34 | 100.00 | Using index condition; Using where | | 2 | DEPENDENT SUBQUERY | tab | index_subquery | idx_abc | idx_abc | 8 | func,const | 1 | 100.00 | Using index | +----+--------------------+-------+----------------+---------------+---------+---------+------------+------+----------+------------------------------------+
mysql> show warnings\G *************************** 1. row *************************** Level: Note Code: 1003 Message: /* select#1 */ select /*+ NO_SEMIJOIN(@`qb1`) */ `rep`.`tab`.`id` AS `id`,`rep`.`tab`.`a` AS `a`,`rep`.`tab`.`b` AS `b`,`rep`.`tab`.`c` AS `c`,`rep`.`tab`.`padding` AS `padding` from `rep`.`tab` where ((`rep`.`tab`.`a` = 1) and (`rep`.`tab`.`b` between 100 and 200) and <in_optimizer>(`rep`.`tab`.`c`,<exists>(<index_lookup>(<cache>(`rep`.`tab`.`c`) in tab on idx_abc)))) 1 row in set (0.00 sec)
mysql> show warnings\G *************************** 1. row *************************** Level: Note Code: 1003 Message: /* select#1 */ select /*+ NO_SEMIJOIN(@`qb1`) */ `rep`.`tab`.`id` AS `id`,`rep`.`tab`.`a` AS `a`,`rep`.`tab`.`b` AS `b`,`rep`.`tab`.`c` AS `c`,`rep`.`tab`.`padding` AS `padding` from `rep`.`tab` where ((`rep`.`tab`.`a` = 1) and <in_optimizer>(`rep`.`tab`.`id`,<exists>(<primary_index_lookup>(<cache>(`rep`.`tab`.`id`) in tab on PRIMARY))))