文章目录
1.查询优化-Explain语句详解上
1.1前言
- 一条查询语句在经过 MySQL 查询优化器的各种基于成本和规则的优化会后生成一个所谓的 执行计划 ,这个执行计划展示了接下来具体执行查询的方式,比如可能使用的索引、实际使用的索引、以及使用的索引长度
- 可以使用EXPLAIN 语句来帮助我们查看某个查询语句的具体执行计划,例如:
mysql> EXPLAIN SELECT 1;
+----+-------------+-------+------------+------+---------------+------+---------+------+--
----+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | r
ows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+--
----+----------+----------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | N
ULL | NULL | No tables used |
+----+-------------+-------+------------+------+---------------+------+---------+------+--
----+----------+----------------+
1 row in set, 1 warning (0.01 sec)
-
EXPLAIN 语句输出的各个列的作用:
- id: 在一个大的查询语句中每个 SELECT 关键字都对应一个唯一的 id
- select_type :SELECT 关键字对应的那个查询的类型
- table 表名
- partitions 匹配的分区信息
- type :针对单表的访问方法
- possible_keys :可能用到的索引
- key :实际上使用的索引
- key_len :实际使用到的索引长度
- ref:当使用索引列等值查询时,与索引列进行等值匹配的对象信息
- rows:预估的需要读取的记录条数
- filtered:某个表经过搜索条件过滤后剩余记录条数的百分比
- Extra 一些额外的信息
-
测试表:single_table表
-
我们仍然假设有两个和 single_table 表构造一模一样的 s1 、 s2 表,而且这两个表里边儿有10000条记录,除 id列外其余的列都插入随机值
CREATE TABLE single_table (
id INT NOT NULL AUTO_INCREMENT,
key1 VARCHAR(100),
key2 INT,
key3 VARCHAR(100),
key_part1 VARCHAR(100),
key_part2 VARCHAR(100),
key_part3 VARCHAR(100),
common_field VARCHAR(100),
PRIMARY KEY (id),
KEY idx_key1 (key1),
UNIQUE KEY idx_key2 (key2),
KEY idx_key3 (key3),
KEY idx_key_part(key_part1, key_part2, key_part3)
) Engine=InnoDB CHARSET=utf8;
1.2执行计划输出各列详解
1.2.1 table
-
定EXPLAIN语句输出的每条记录都对应着某个单表的访问方法,该条记录的table列代表着该表 的表名
-
单表测试:只涉及对 s1 表的单表查询,所以 EXPLAIN 输出中只有一条记录
mysql> EXPLAIN SELECT * FROM s1; +----+-------------+-------+------------+------+---------------+------+---------+------+-- ----+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | r ows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+-- ----+----------+-------+ | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9 688 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+------+---------+------+-- ----+----------+-------+ 1 row in set, 1 warning (0.00 sec)
-
连接查询:到这个连接查询的执行计划中有两条记录,这两条记录的 table 列分别是 s1 和 s2 ,这两条记录用来分 别说明对 s1 表和 s2 表的访问方法是什么
mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2; +----+-------------+-------+------------+------+---------------+------+---------+------+-- ----+----------+---------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | r ows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+-- ----+----------+---------------------------------------+ | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9 688 | 100.00 | NULL | | 1 | SIMPLE | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9 954 | 100.00 | Using join buffer (Block Nested Loop) | +----+-------------+-------+------------+------+---------------+------+---------+------+-- ----+----------+---------------------------------------+ 2 rows in set, 1 warning (0.01 sec)
1.2.2 id
- 查询语句中每出现一个 SELECT 关键字,MySQL 就会为它分配一个唯一的 id 值
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';
+----+-------------+-------+------------+------+---------------+----------+---------+-----
--+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref
| rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-----