本文为大家介绍MySQL查看执行计划时,extra常见的额外信息
Using index
表示使用了覆盖索引,即通过索引树可以直接获取数据,不需要回表。
表结构:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
select id from t1 where id=1;
select name from t1 where name=‘aaa’;
select id from t1 where name=‘aaa’;
Using where
使用了where查询,但是条件字段上没有索引
表结构:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
select name from t1 where age=11;
select * from t1 where age=11;
Using temporary
查询过程中需要使用临时表做为中间结果集
表结构:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
---------------------------------------------
CREATE TABLE `t2` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
复现SQL
select a.* from t1 as a LEFT JOIN t2 as b on a.id=b.id order by b.age desc ;
with tmp as (select name from t2)
select * from t1 where name in (select * from tmp);
Using filesort
查询中使用了排序,同时排序没有直接使用索引
表结构:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
select name from t1 ORDER BY age;
select * from t1 ORDER BY name;
Using join buffer (Block Nested Loop)
关联查询时使用了块嵌套循环连接
表结构
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
-------------------------------------------------------
CREATE TABLE `t2` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
select a.* from t1 as a left JOIN t2 as b on a.age=b.age ;
select * from t1 as a left JOIN t2 as b on a.name=b.name ;
Impossible where
查询时where的条件不可能为真,所以将返回空结果集
表结构
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
select * from t1 where 1=2;
Select tables optimized away
查询时某些表没有被使用,从而被优化掉
表结构
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
select max(id) from t1;
select min(name) from t1;
Using index condition
使用了索引范围扫描,且需要回表
表结构
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
select * from t1 where name>‘aaa’;
LooseScan\FirstMatch(tbl_name)
将In子查询转为semi-join时,如果采用的是LooseScan执行策略,则在驱动表执行计划的Extra列就是显示LooseScan提示
将In子查询转为semi-join时,如果采用的是FirstMatch执行策略,则在被驱动表执行计划的Extra列就是显示FirstMatch(tbl_name)提示
表结构
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
-----------------------------------------------------------
CREATE TABLE `t2` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB
复现SQL
当t2中数据量较多时
select * from t1 where name in (select name from t2)
FirstMatch(t1)
当t2中数据量较少时
select * from t1 where name in (select name from t2)
LooseScan
其实这两个情况的不同是因为优化器判断全扫描out_tables和inner_tables哪个代价更小来决定具体使用哪个策略
彩蛋
优化器的执行流程实际是通过层层计算每个表的最佳访问路径来决定的,如果找到更优的执行计划则更新,否则优化结束。简单的说就是“动态规划+贪心算法”的过程