MySQL-09-SQL执行计划
2024-10-02 09:10:44
SQL执行计划获取及分析
介绍
(1)获取到的是优化器选择完成的,他认为代价最小的执行计划.
作用: 语句执行前,先看执行计划信息,可以有效的防止性能较差的语句带来的性能问题.
如果业务中出现了慢语句,我们也需要借助此命令进行语句的评估,分析优化方案
(2) select语句获取数据的方法
1. 全表扫描(应当尽量避免,因为性能低)
2. 索引扫描
3. 获取不到数据
SQL执行计划获取
sql文件下载链接:
https://alnk-blog-pictures.oss-cn-shenzhen.aliyuncs.com/blog-pictures/world.sql
https://alnk-blog-pictures.oss-cn-shenzhen.aliyuncs.com/blog-pictures/t100w.txt
导入数据库
mysql> source /root/world.sql
mysql> source /root/t100w.txt
获取优化器选择后的sql执行计划
mysql> use test
mysql> desc select * from t100w where id=9000;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t100w | ALL | NULL | NULL | NULL | NULL | 997470 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)
mysql> use test
mysql> explain select * from t100w where id=9000\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t100w # 查询的表
type: ALL # 查询类型
possible_keys: NULL # 可能走的索引
key: NULL # 走的索引名
key_len: NULL # 应用索引的长度
ref: NULL
rows: 997470 # 查询结果集的长度
Extra: Using where # 额外信息
1 row in set (0.00 sec)
SQL执行计划分析
mysql> use world;
mysql> desc select * from city where countrycode = 'CHN'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
type: ref
possible_keys: CountryCode
key: CountryCode
key_len: 3
ref: const
rows: 363
Extra: Using index condition
1 row in set (0.00 sec)
重点关注的信息
table: city ---->查询操作的表 **
possible_keys: CountryCode ---->可能会走的索引 **
key: CountryCode ---->真正走的索引 ***
type: ref ---->索引类型 *****
Extra: Using index condition ---->额外信息 *****
type详解
从左到右性能依次变好: ALL --> INDEX -->RANGE -->ref --> eq_ref --> system,const
ALL:全表扫描,不走索引
1 查询条件列,没有索引
mysql> use test
mysql> show index from t100w;
# 结果没有索引
Empty set (0.00 sec)
mysql> desc SELECT * FROM t100w WHERE k2='780P';
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t100w | ALL | NULL | NULL | NULL | NULL | 997470 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)
2 查询条件出现以下语句, (有辅助索引列)也不走索引
mysql> USE world
mysql> DESC city; #MUL :辅助索引(单列,联和,前缀)
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Name | char(35) | NO | | | |
| CountryCode | char(3) | NO | MUL | | |
| District | char(20) | NO | | | |
| Population | int(11) | NO | | 0 | |
+-------------+----------+------+-----+---------+----------------+
mysql> DESC SELECT * FROM city WHERE countrycode <> 'CHN';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | city | ALL | CountryCode | NULL | NULL | NULL | 4188 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
mysql> DESC SELECT * FROM city WHERE countrycode NOT IN ('CHN','USA');
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | city | ALL | CountryCode | NULL | NULL | NULL | 4188 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
mysql> DESC SELECT * FROM city WHERE countrycode LIKE '%CH%';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4188 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
注意:对于聚集索引列,使用以上语句,依然会走索引
mysql> DESC SELECT * FROM city WHERE id <> 10;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | city | range | PRIMARY | PRIMARY | 4 | NULL | 2103 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
INDEX:全索引扫描
1. 查询需要获取整个索引树种的值时
mysql> use world
mysql> DESC SELECT countrycode FROM city;
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
| 1 | SIMPLE | city | index | NULL | CountryCode | 3 | NULL | 4188 | Using index |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
1 row in set (0.00 sec)
2. 联合索引中,任何一个非最左列作为查询条件时
idx_a_b_c(a,b,c) ---> a ab abc
SELECT * FROM t1 WHERE b
SELECT * FROM t1 WHERE c
RANGE :索引范围扫描
辅助索引
> < >= <= LIKE IN OR
主键
<> NOT IN
mysql> DESC SELECT * FROM city WHERE id<5;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | city | range | PRIMARY | PRIMARY | 4 | NULL | 4 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> DESC SELECT * FROM city WHERE countrycode LIKE 'CH%';
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-----------------------+
| 1 | SIMPLE | city | range | CountryCode | CountryCode | 3 | NULL | 397 | Using index condition |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
mysql> DESC SELECT * FROM city WHERE countrycode IN ('CHN','USA');
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-----------------------+
| 1 | SIMPLE | city | range | CountryCode | CountryCode | 3 | NULL | 637 | Using index condition |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
注意:
1和2例子中,可以享受到B+树的优势,但是3例子中是不能享受的.
所以,我们可以将3号列子改写:
mysql> DESC SELECT * FROM city WHERE countrycode='CHN'
-> UNION ALL
-> SELECT * FROM city WHERE countrycode='USA';
+----+--------------+------------+------+---------------+-------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+---------------+-------------+---------+-------+------+-----------------------+
| 1 | PRIMARY | city | ref | CountryCode | CountryCode | 3 | const | 363 | Using index condition |
| 2 | UNION | city | ref | CountryCode | CountryCode | 3 | const | 274 | Using index condition |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+---------------+-------------+---------+-------+------+-----------------------+
3 rows in set (0.00 sec)
ref: 非唯一性索引,等值查询
mysql> DESC SELECT * FROM city WHERE countrycode='CHN';
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | city | ref | CountryCode | CountryCode | 3 | const | 363 | Using index condition |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)
eq_ref: 在多表连接时,连接条件使用了唯一索引(uk pK)
mysql> DESC SELECT b.name,a.name FROM city AS a
-> JOIN country AS b
-> ON a.countrycode=b.code
-> WHERE a.population <100;
+----+-------------+-------+------+---------------+-------------+---------+--------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+--------------+------+-------------+
| 1 | SIMPLE | b | ALL | PRIMARY | NULL | NULL | NULL | 239 | NULL |
| 1 | SIMPLE | a | ref | CountryCode | CountryCode | 3 | world.b.Code | 9 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+--------------+------+-------------+
2 rows in set (0.00 sec)
system,const :唯一索引的等值查询
mysql> DESC SELECT * FROM city WHERE id=10;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | city | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)
其他字段解释
extra字段:
Using filesort: 文件排序 出现这个说明需要排序,会影响查询速度
mysql> SHOW INDEX FROM city\G;
*************************** 1. row ***************************
Table: city
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: ID
Collation: A
Cardinality: 4188
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: city
Non_unique: 1
Key_name: CountryCode
Seq_in_index: 1
Column_name: CountryCode
Collation: A
Cardinality: 465
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
# 创建单列普通索引(未解决问题,还是有Using filesort)
mysql> ALTER TABLE city ADD INDEX CountryCode(CountryCode);
mysql> ALTER TABLE city DROP INDEX idx_c_p;
mysql> DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
type: ref
possible_keys: CountryCode
key: CountryCode
key_len: 3
ref: const
rows: 363
Extra: Using index condition; Using where; Using filesort
# 创建单列普通索引(未解决问题,还是有Using filesort)
mysql> ALTER TABLE city ADD INDEX idx_(population);
mysql> DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
type: ref
possible_keys: CountryCode
key: CountryCode
key_len: 3
ref: const
rows: 363
Extra: Using index condition; Using where; Using filesort
# 创建联合索引(问题解决)
mysql> ALTER TABLE city ADD INDEX idx_c_p(countrycode,population);
mysql> ALTER TABLE city DROP INDEX idx_;
mysql> ALTER TABLE city DROP INDEX CountryCode;
mysql> DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
type: ref
possible_keys: idx_c_p
key: idx_c_p
key_len: 3
ref: const
rows: 363
Extra: Using index condition; Using where
# 此时这里的 Using filesort 排序已经不存在了,查询数据会变快
结论:
1.当我们看到执行计划extra位置出现filesort,说明有文件排序出现
2.观察需要排序(ORDER BY,GROUP BY ,DISTINCT)的条件,有没有索引
3.根据子句的执行顺序,去创建联合索引
索引优化效果测试
优化前:
[root@db01 ~]# mysqlslap --defaults-file=/etc/my.cnf \
> --concurrency=100 --iterations=1 --create-schema='test' \
> --query="select * from test.t100w where k2='780P'" engine=innodb \
> --number-of-queries=2000 -uroot -proot123 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
Running for engine rbose
Average number of seconds to run all queries: 701.743 seconds
Minimum number of seconds to run all queries: 701.743 seconds
Maximum number of seconds to run all queries: 701.743 seconds
Number of clients running queries: 100
Average number of queries per client: 20
优化后:
[root@db01 ~]# mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='780P'" engine=innodb --number-of-queries=2000 -uroot -proot123 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
Running for engine rbose
Average number of seconds to run all queries: 0.190 seconds
Minimum number of seconds to run all queries: 0.190 seconds
Maximum number of seconds to run all queries: 0.190 seconds
Number of clients running queries: 100
Average number of queries per client: 20
联合索引创建注意事项
1.SELECT * FROM t1 WHERE a= b=
我们建立联合索引时:
ALTER TABLE t1 ADD INDEX idx_a_b(a,b);
ALTER TABLE t1 ADD INDEX idx_b_a(b,a);
以上的查询不考虑索引的顺序,优化器会自动调整where的条件顺序
注意: 索引,我们在这种情况下建索引时,需要考虑哪个列的唯一值更多,哪个放在索引左边.
2.如果有where条件中出现不等值查询条件
mysql> use test;
mysql> DESC SELECT * FROM t100w WHERE num <1000 AND k2='DEEF';
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t100w | ALL | NULL | NULL | NULL | NULL | 997470 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
我们建索引时:
mysql> ALTER TABLE t100w ADD INDEX idx_2_n(k2,num);
语句书写时
mysql> DESC SELECT * FROM t100w WHERE k2='DEEF' AND num <1000;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
| 1 | SIMPLE | t100w | range | idx_2_n | idx_2_n | 22 | NULL | 2 | Using index condition |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
1 row in set (0.12 sec)
3. 如果查询中出现多子句
我们要按照子句的执行顺序进行建立索引
explain(desc)使用场景
公司业务慢,请你从数据库的角度分析原因
1.mysql出现性能问题,总结有两种情况
(1)应急性的慢:突然夯住
应急情况:数据库hang(卡了,资源耗尽)
处理过程:
1.show processlist获取到导致数据库hang的语句。然后kill ID杀掉这条语句的进程
2.explain分析SQL的执行计划,有没有走索引,索引的类型情况
3.建索引,改语句
(2)一段时间慢(持续性的)
1.记录慢日志slowlog,分析slowlog
2.explain分析SQL的执行计划,有没有走索引,索引的类型情况
3.建索引,改语句
最新文章
- UML图中经常用到几种的关系图例
- SqlServer性能优化 查询和索引优化(十二)
- Linux shell basic3 dd wc comm chmod ls
- CentOS 6.4安装Apache+MySQL+PHP的图文教程
- MySQL修改root密码的各种方法整理
- C语言初学者代码中的常见错误与瑕疵(4)
- Sum Root to Leaf Numbers [LeetCode]
- Google Guava学习笔记——基础工具类针对Object类的使用
- Java多线程——Semaphore信号灯
- Android 实现ListView异步加载图片
- 构建基于Javascript的移动web CMS——加入jQuery插件
- 依据不同的操作系统读取配置文件/java读取属性文件代码
- tab切换☆☆☆☆☆
- Tornado-StaticFileHandler参考
- 01迷宫 洛谷 p1141
- 利用rsync+inotify实现数据实时同步脚本文件
- all unicode
- Spring Boot 2.x 编写 RESTful API (一) RESTful API 介绍 &; RestController
- Maven基础入门与核心知识
- Ubuntu16.04 创建和使用虚拟环境
热门文章
- AcWing 1127. 香甜的黄油
- 并发王者课-铂金10:能工巧匠-ThreadLocal如何为线程打造私有数据空间
- [Vue入门及介绍,基础使用、MVVM架构、插值表达式、文本指令、事件指令]
- Windows环境mysql自动备份
- spring、springmvc、springboot、springcloud的联系与区别
- 「CF521D」 Shop
- C语言:toascii()函数
- C语言:printf(";";)标志详解
- CF1329F题解
- springMVC-12-整合spring和springmvc