MySQL--------SQL优化审核工具实战
1. 背景
SQLAdvisor是由美团点评公司技术工程部DBA团队(北京)开发维护的一个分析SQL给出索引优化建议的工具。它基于MySQL原生态词法解析,结合分析SQL中的where条件、聚合条件、多表Join关系 给出索引优化建议。目前SQLAdvisor在美团点评内部广泛应用,公司内部对SQLAdvisor的开发全面转到github上,开源和内部使用保持一致。
在数据库运维过程中,优化SQL是业务团队与DBA团队的日常任务。例行SQL优化,不仅可以提升程序性能,还能够降低线上故障的概率。
目前常用的SQL优化方式包括但不限于:业务层优化、SQL逻辑优化、索引优化等。其中索引优化通常通过调整索引或新增索引从而达到SQL优化的目的。索引优化往往可以在短时间内产生非常巨大的效果。如果能够将索引优化转化成工具化、标准化的流程,减少人工介入的工作量,无疑会大大提高DBA的工作效率。板面的做法和配料
2. 架构流程图

3. 环境
* os version
|
1
2
3
4
5
6
7
8
9
10
11
|
[root@SQLAdvisor ~]# cat /etc/redhat-release CentOS release 6.8 (Final)[root@SQLAdvisor ~]# uname -r2.6.32-642.3.1.el6.x86_64[root@SQLAdvisor ~]# uname -nSQLAdvisor[root@SQLAdvisor ~]# getenforce Disabled |
* mysql version
|
1
2
3
4
5
6
7
|
mysql> show variables like 'version';+---------------+--------+| Variable_name | Value |+---------------+--------+| version | 5.7.18 |+---------------+--------+1 row in set (0.00 sec) |
4. 安装SQLAdvisor
* 获取最新代码
|
1
2
3
4
5
6
|
[root@SQLAdvisor ~]# git clone https://github.com/Meituan-Dianping/SQLAdvisor.gitInitialized empty Git repository in /root/SQLAdvisor/.git/remote: Counting objects: 1460, done.remote: Total 1460 (delta 0), reused 0 (delta 0), pack-reused 1460Receiving objects: 100% (1460/1460), 19.92 MiB | 209 KiB/s, done.Resolving deltas: 100% (368/368), done. |
* 安装依赖项
|
1
2
3
4
5
6
7
|
[root@SQLAdvisor ~]# yum -y install cmake libaio-devel libffi-devel glib2 glib2-devel[root@SQLAdvisor ~]# yum -y install [root@SQLAdvisor ~]# yum -y install Percona-Server-shared-56 [root@SQLAdvisor ~]# ln -s /usr/lib64/libperconaserverclient_r.so.18 /usr/lib64/libperconaserverclient_r.so |
* 编译依赖项sqlparser
|
1
2
3
4
5
|
[root@SQLAdvisor ~]# cd SQLAdvisor/[root@SQLAdvisor SQLAdvisor]# cmake -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=debug -DCMAKE_INSTALL_PREFIX=/usr/local/sqlparser ./[root@SQLAdvisor SQLAdvisor]# make && make install |
* 安装SQLAdvisor
|
1
2
3
4
5
|
[root@SQLAdvisor SQLAdvisor]# cd sqladvisor/[root@SQLAdvisor sqladvisor]# cmake -DCMAKE_BUILD_TYPE=debug ./[root@SQLAdvisor sqladvisor]# make |
* SQLAdvisor Info
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[root@SQLAdvisor sqladvisor]# ./sqladvisor --helpUsage: sqladvisor [OPTION...] sqladvisorSQL Advisor SummaryHelp Options: -?, --help Show help optionsApplication Options: -f, --defaults-file sqls file -u, --username username -p, --password password -P, --port port -h, --host host -d, --dbname database name -q, --sqls sqls -v, --verbose 1:output logs 0:output nothing |
5. 测试
* 生成测试数据表
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
mysql> create database test1 character set utf8mb4;Query OK, 1 row affected (0.00 sec)mysql> create table user( -> id INT PRIMARY KEY AUTO_INCREMENT, -> name VARCHAR(64) NOT NULL, -> age int, -> sex int -> )ENGINE=INNODB DEFAULT CHARSET=utf8mb4;Query OK, 0 rows affected (0.13 sec)mysql> desc user;+-------+-------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------+-------------+------+-----+---------+----------------+| id | int(11) | NO | PRI | NULL | auto_increment || name | varchar(64) | NO | | NULL | || age | int(11) | YES | | NULL | || sex | int(11) | YES | | NULL | |+-------+-------------+------+-----+---------+----------------+4 rows in set (0.01 sec) |
* 生成测试数据
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
mysql> insert into user(name,age, sex) select 'lisea', 25, 1;Query OK, 1 row affected (0.01 sec)Records: 1 Duplicates: 0 Warnings: 0mysql> insert into user(name,age, sex) select concat(name, '1'), age+1, sex+1 from user;Query OK, 1 row affected (0.02 sec)Records: 1 Duplicates: 0 Warnings: 0mysql> insert into user(name,age, sex) select concat(name, '2'), age+2, sex from user;Query OK, 2 rows affected (0.02 sec)Records: 2 Duplicates: 0 Warnings: 0mysql> insert into user(name,age, sex) select concat(name, '3'), age+2, sex from user;Query OK, 4 rows affected (0.18 sec)Records: 4 Duplicates: 0 Warnings: 0......mysql> insert into user(name,age, sex) select concat(name, '10'), age+2, sex from user;Query OK, 512 rows affected (0.24 sec)Records: 512 Duplicates: 0 Warnings: 0mysql> insert into user(name,age, sex) select concat(name, '11'), age+4, sex from user;Query OK, 1024 rows affected (0.79 sec)Records: 1024 Duplicates: 0 Warnings: 0mysql> select count(1) from user;+----------+| count(1) |+----------+| 2048 |+----------+1 row in set (0.01 sec) |
* 命令行传参调用测试SQLAdvisor [查找非索引行]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
[root@SQLAdvisor sqladvisor]# ./sqladvisor -h 127.0.0.1 -P 3306 -u root -p '123' -d test1 -q "select * from user where name = 'lisea'" -v 12017-10-27 05:35:49 34059 [Note] 第1步: 对SQL解析优化之后得到的SQL:select `*` AS `*` from `test1`.`user` where (`name` = 'lisea') 2017-10-27 05:35:49 34059 [Note] 第2步:开始解析where中的条件:(`name` = 'lisea') 2017-10-27 05:35:49 34059 [Note] show index from user 2017-10-27 05:35:49 34059 [Note] show table status like 'user' 2017-10-27 05:35:49 34059 [Note] select count(*) from ( select `name` from `user` FORCE INDEX( PRIMARY ) order by id DESC limit 1024) `user` where (`name` = 'lisea') 2017-10-27 05:35:49 34059 [Note] 第3步:表user的行数:2048,limit行数:1024,得到where条件中(`name` = 'lisea')的选择度:1024 2017-10-27 05:35:49 34059 [Note] 第4步:开始验证 字段name是不是主键。表名:user 2017-10-27 05:35:49 34059 [Note] show index from user where Key_name = 'PRIMARY' and Column_name ='name' and Seq_in_index = 1 2017-10-27 05:35:49 34059 [Note] 第5步:字段name不是主键。表名:user 2017-10-27 05:35:49 34059 [Note] 第6步:开始验证 字段name是不是主键。表名:user 2017-10-27 05:35:49 34059 [Note] show index from user where Key_name = 'PRIMARY' and Column_name ='name' and Seq_in_index = 1 2017-10-27 05:35:49 34059 [Note] 第7步:字段name不是主键。表名:user 2017-10-27 05:35:49 34059 [Note] 第8步:开始验证表中是否已存在相关索引。表名:user, 字段名:name, 在索引中的位置:1 2017-10-27 05:35:49 34059 [Note] show index from user where Column_name ='name' and Seq_in_index =1 2017-10-27 05:35:49 34059 [Note] 第9步:开始输出表user索引优化建议: 2017-10-27 05:35:49 34059 [Note] Create_Index_SQL:alter table user add index idx_name(name) 2017-10-27 05:35:49 34059 [Note] 第10步: SQLAdvisor结束! |
* 命令行传参调用测试SQLAdvisor [查找索引行]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
[root@SQLAdvisor sqladvisor]# ./sqladvisor -h 127.0.0.1 -P 3306 -u root -p '123' -d test1 -q "select * from user where id = 1" -v 12017-10-27 05:36:46 34062 [Note] 第1步: 对SQL解析优化之后得到的SQL:select `*` AS `*` from `test1`.`user` where (`id` = 1) 2017-10-27 05:36:46 34062 [Note] 第2步:开始解析where中的条件:(`id` = 1) 2017-10-27 05:36:46 34062 [Note] show index from user 2017-10-27 05:36:46 34062 [Note] show table status like 'user' 2017-10-27 05:36:46 34062 [Note] select count(*) from ( select `id` from `user` FORCE INDEX( PRIMARY ) order by id DESC limit 1024) `user` where (`id` = 1) 2017-10-27 05:36:46 34062 [Note] 第3步:表user的行数:2048,limit行数:1024,得到where条件中(`id` = 1)的选择度:1024 2017-10-27 05:36:46 34062 [Note] 第4步:开始验证 字段id是不是主键。表名:user 2017-10-27 05:36:46 34062 [Note] show index from user where Key_name = 'PRIMARY' and Column_name ='id' and Seq_in_index = 1 2017-10-27 05:36:46 34062 [Note] 第5步:字段id是主键。表名:user 2017-10-27 05:36:46 34062 [Note] 第6步:表user 经过运算得到的索引列首列是主键,直接放弃,没有优化建议 2017-10-27 05:36:46 34062 [Note] 第7步: SQLAdvisor结束! |
* 配置文件传参调用
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
[root@SQLAdvisor sqladvisor]# cat sql.cnf [sqladvisor]username=rootpassword=123host=127.0.0.1port=3306dbname=test1sqls=select * from user where name = 'lisea'[root@SQLAdvisor sqladvisor]# ./sqladvisor -f sql.cnf -v 12017-10-27 05:40:14 34070 [Note] 第1步: 对SQL解析优化之后得到的SQL:select `*` AS `*` from `test1`.`user` where (`name` = 'lisea') 2017-10-27 05:40:14 34070 [Note] 第2步:开始解析where中的条件:(`name` = 'lisea') 2017-10-27 05:40:14 34070 [Note] show index from user 2017-10-27 05:40:14 34070 [Note] show table status like 'user' 2017-10-27 05:40:14 34070 [Note] select count(*) from ( select `name` from `user` FORCE INDEX( PRIMARY ) order by id DESC limit 1024) `user` where (`name` = 'lisea') 2017-10-27 05:40:14 34070 [Note] 第3步:表user的行数:2048,limit行数:1024,得到where条件中(`name` = 'lisea')的选择度:1024 2017-10-27 05:40:14 34070 [Note] 第4步:开始验证 字段name是不是主键。表名:user 2017-10-27 05:40:14 34070 [Note] show index from user where Key_name = 'PRIMARY' and Column_name ='name' and Seq_in_index = 1 2017-10-27 05:40:14 34070 [Note] 第5步:字段name不是主键。表名:user 2017-10-27 05:40:14 34070 [Note] 第6步:开始验证 字段name是不是主键。表名:user 2017-10-27 05:40:14 34070 [Note] show index from user where Key_name = 'PRIMARY' and Column_name ='name' and Seq_in_index = 1 2017-10-27 05:40:14 34070 [Note] 第7步:字段name不是主键。表名:user 2017-10-27 05:40:14 34070 [Note] 第8步:开始验证表中是否已存在相关索引。表名:user, 字段名:name, 在索引中的位置:1 2017-10-27 05:40:14 34070 [Note] show index from user where Column_name ='name' and Seq_in_index =1 2017-10-27 05:40:14 34070 [Note] 第9步:开始输出表user索引优化建议: 2017-10-27 05:40:14 34070 [Note] Create_Index_SQL:alter table user add index idx_name(name) 2017-10-27 05:40:14 34070 [Note] 第10步: SQLAdvisor结束! |
MySQL--------SQL优化审核工具实战的更多相关文章
- mysql sql优化实例
mysql sql优化实例 优化前: pt-query-degist分析结果: # Query 3: 0.00 QPS, 0.00x concurrency, ID 0xDC6E62FA021C85B ...
- sql自动审核工具-inception
[inception使用规范及说明文档](http://mysql-inception.github.io/inception-document/usage/)[代码仓库](https://githu ...
- Mysql SQL优化&执行计划
SQL优化准则 禁用select * 使用select count(*) 统计行数 尽量少运算 尽量避免全表扫描,如果可以,在过滤列建立索引 尽量避免在where子句对字段进行null判断 尽量避免在 ...
- 18.Mysql SQL优化
18.SQL优化18.1 优化SQL语句的一般步骤 18.1.1 通过show status命令了解各种SQL的执行频率show [session|global] status; -- 查看服务器状态 ...
- mysql sql优化及注意事项
sql优化分析 通过slow_log等方式可以捕获慢查询sql,然后就是减少其对io和cpu的使用(不合理的索引.不必要的数据访问和排序)当我们面对具体的sql时,首先查看其执行计划A.看其是否使用索 ...
- MySQL sql优化(摘抄自文档)
前言 有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧. 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础. 优化目标 ...
- MySQL SQL优化
一.优化数据库的一般步骤: (A) 通过 show status 命令了解各种SQL的执行频率. (B) 定位执行效率较低的SQL语句,方法两种: 事后查询定位:慢查询日志:--log-slow-qu ...
- MySQL SQL优化之in与range查询【转】
本文来自:http://myrock.github.io/ 首先我们来说下in()这种方式的查询.在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效 ...
- MySql Sql 优化技巧分享
有天发现一个带inner join的sql 执行速度虽然不是很慢(0.1-0.2),但是没有达到理想速度.两个表关联,且关联的字段都是主键,查询的字段是唯一索引. sql如下: SELECT p_it ...
随机推荐
- Note 2: Complain
Note 2: Complain 1. The collection of Linkun's [1]: 1.1suck If someone says that something sucks, th ...
- Django之会话机制cookie、session使用
login视图函数: def login(request): if request.method == 'POST': username = request.POST.get('username') ...
- 【转帖】深挖NUMA
深挖NUMA http://www.litrin.net/2017/10/31/深挖numa/ 首先列出本站之前相关的几篇帖子: Linux的NUMA机制 NUMA对性能的影响 cgroup的cpus ...
- 服务器TIME_WAIT和CLOSE_WAIT区别及解决方案
系统上线之后,通过如下语句查看服务器时,发现有不少TIME_WAIT和CLOSE_WAIT. netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) ...
- 【洛谷】P4883 mzf的考验
[洛谷]P4883 mzf的考验 最近忽然放弃治疗开始随机跳题了 感觉还行 就是必须吸氧感觉有点糟糕... 这题翻转和求和都是平衡树基本操作,那个异或可以通过维护树中\(2\)进制下第\(2^{i}\ ...
- [DEBUG] Spring boot前端html无法下载示例文件
更新:原方法打jar包的时候是可以的,后来我打war包之后下载的文件就是0字节.尴尬:) 所以现在更换一种方法,然后打war包.在服务器已测试成功. 前端不需要改变,只需要更改controller: ...
- 剑指offer39:平衡二叉树
1 题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 2 思路和方法 平衡二叉树,又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1 ...
- C结构体与JavaBean转化
1 概述 (1)项目开发过程可能涉及多种语言,而多种语言之间如何数据交换格式是多种多样的,比如说:Java和JavaScript可以用json,Java和C#可以用xml等等. (2)这里提供一种C与 ...
- java7:核心技术与最佳实践读书笔记——字节代码格式
一般流程:开发人员写出java源代码(.java) -> javac(编译器) -> java字节代码(.class) -> 加载 -> java虚拟机(jvm)运行. 1. ...
- 【原创】编程基础之Jekins
Jenkins 2.164.2 官方:https://jenkins.io 一 简介 Build great things at any scale The leading open source a ...