使用的是https://dev.mysql.com/doc/sakila-db.zip里面的例子
--SQL优化语句的一般步骤
--1.通过show status命令了解各种SQL的执行频率
--2.定位执行效率较低的SQL语句
--3.通过EXPLAIN分析较低SQL的执行计划
--4.通过show profile分析SQL
--5.通过trace分析优化器如何选择执行计划
--6.确定问题并采取相应的优化措施
--1.通过show status命令了解各种SQL的执行频率
--显示了当前session中所有统计参数的值
show status like 'Com_%'
Com_xxx表示每个xxx语句执行的次数,比较关注的统计参数
Com_select Com_insert Com_update Com_delete
以上参数对所有存储引擎都会进行累计 下面参数只对InnoDB进行累计
InnoDB_rows_read:select查询返回行数
InnoDB_rows_inserted:insert查询返回行数
InnoDB_rows_updated:update操作更新行数
InnoDB_rows_deleted:执行delete操作删除行数
通过以上参数了解当前数据库应用是以插入更新为主还是以查询操作为主,各类型的SQL大致的执行比例是多少。更新操作计数是对执行次数的统计 (包括提交和回滚)
事务型应用 通过Com_commit和Com_rollback可以了解事务提交回滚情况 对于回滚操作很频繁的数据库 意味着应用编写存在问题
Connections:试图连接Mysql服务器次数
Uptime:服务器工作时间
Slow_queries:慢查询次数
--2.定位执行效率较低的SQL语句
通过以下两种方式定位效率低的SQL语句
1.通过慢查询日志定位哪些执行效率较低的SQL语句 用--log-slow-queries[=file_name]启动mysqld写一个包含所有执行时间超过Long_query_time秒的SQL语句的日志(查看日志管理部分)
2.慢查询日志在查询结束后才记录 在应用反映执行效率出现问题无法用慢日志定位问题 使用show processlist命令查看当前MySQL在进行的线程 可以查看报过线程状态 是否锁表等 可以实时查看SQL的执行情况 同时对一些锁表进行优化。
--3.通过EXPLAIN分析较低SQL的执行计划
查到低效率SQL语句后 通过EXPLAIN or DESC获取MySQL如何执行select语句信息 包括在select语句执行过程中表如何连接和连接的顺序
--example:
explain select sum(amount) from customer a,payment b where 1=1 and a.customer_id = b.customer_id and email = '[email protected]'\G
参数介绍:
select_type:表示SELECT的类型 常见取值有SIMPLE(简单表 不使用表连接或者子查询) PRIMARY(主查询 外层的查询) UNION(UNION中的第二个或者后面的查询语句) SUBQUERY(子查询中的第一个select)
table:输出结果集的表
type:表示MySQL在表中找到所需行的方式 或者访问类型 常见类型如图
ALL | index |
range |
ref |
eq_ref |
const,system |
NULL |
从左至右 性能由差->好
all:全表扫描 MySQL遍历全表来找到匹配的行
index:索引全扫描 Mysql遍历整个索引查询匹配行
range:索引范围扫描 常见于 < <= > >= between
ref:使用非唯一索引扫描或唯一索引的前缀扫描 返回某个单独值得记录行 ref还经常出现在join操作中
eq_ref:类似ref 区别使用的是唯一索引 对于每个索引键值 表中只有一个值 (就是多表连接中使用primary key或者unique index作为关联条件)
const,system:单表中最多有一个匹配行 查询起来很迅速 这个匹配行中的其他列值可以被optimizer在当前查询中当作常量处理
NULL:不使用访问表或者索引 直接得到结果
其他值 ref_or_null(类似ref 区别条件中包含对NULL查询) index_merge(索引合并优化) unique_subquery(in的后面是一个查询主键字段的子查询)
index_subquery(与unique_subquery类似 区别在in后面是查询非唯一索引字段的子查询等)
possible_keys:表示查询时可能使用的索引
key:表示实际使用的索引
key_len:使用到索引字段的长度
rows:扫描行数量
EXTRA:执行情况的说明和描述 包含不适合在其他列中显示但对执行计划非常重要的额外信息
————————————————
expain extended命令加上show warnings 能够看到在SQL执行前做了哪些SQL改写
explain extended select sum(amount) from customer a,payment b where 1=1 and a.customer_id = b.customer_id and email = '[email protected]'\G
show warnings\G
从Mysql5.1开始支持分区功能 explain支持分区 EXPLAIN PARTITIONS命令查看SQL访问的分区
例子:
create table customer_part (
`customer_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`store_id` tinyint(3) unsigned NOT NULL,
`first_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
`email` varchar(50) DEFAULT NULL,
`address_id` smallint(5) unsigned NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1',
`create_date` datetime NOT NULL,
`last_update` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`customer_id`)
)partition by hash(`customer_id`) partitions 8;
--插入数据 执行计划检查
insert into customer_part select * from customer;
explain partitions select * from customer_part where customer_id =130\G;
有时候需要选择profile联合分析
--4.通过show profile分析SQL
select @@have_profiling;
select @@profiling;
--默认profiling是关闭的 可以通过set在session级别开启
set profiling=1;
select count(*) from payment;
show profiles语句 看到当前SQL的 Query ID=2
show profile for语句 能够看到执行过程中线程的每个状态和消耗的时间
在sending data状态下 mysql线程往往需要做大量的磁盘读取操作 经常是整个查询中耗时最长的
更清晰查看排序结果 查询INFORMATION_SCHEMA.PROFILE表并按照时间做个desc排序
SET @query_id:=2;
SELECT STATE,SUM(DURATION) AS Total_R,
ROUND(
100 * SUM(DURATION)/
(SELECT SUM(DURATION)
FROM INFORMATION_SCHEMA.PROFILING
WHERE QUERY_ID = @query_id
),2) AS Pct_R,
COUNT(*) AS Calls,
SUM(DURATION) / COUNT(*) AS "R/Call"
FROM INFORMATION_SCHEMA.PROFILING
WHERE QUERY_ID = @query_id
GROUP BY STATE
ORDER BY Total_R DESC;
获取到最消耗时间线程状态后 支持进一步选择all cpu block io context switch page faults等明细类型查看MySQL在使用什么资源上消费了过高时间
--建一张myisam表
create table payment_myisam like payment;
alter table payment_myisam engine=myisam;
insert into payment_myisam select * from payment;
show profiles;
show profile for query 14;
myisam引擎的表在executing之后直接结束查询 完全不需要访问数据
对Mysql源码有兴趣的 可以通过show profile source for query 查看sql解析执行过程中每个步骤对应的源码文件 函数名以及具体的源文件行数
mysql> show profile source for query 14\G;
--5.通过trace分析优化器如何选择执行计划
5.6提供了对sql跟踪trace 通过trace文件 能够进一步了解为什么优化器选择A执行计划而不是B执行计划
用法:打开trace 设置格式为JSON 设置trace最大能够使用的内存大小 避免解析过程中因为默认内存过小而不能够完整显示。
SET OPTIMIZER_TRACE="enabled=on" ,END_MARKERS_IN_JSON=on;
SET OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000;
--SQL语句
select rental_id from rental where 1=1 and rental_date >= '2005-05-25 04:00:00' and rental_date <= '2005-05-25 05:00:00' and inventory_id=4466;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE\G;
--6.确定问题并采取相应的优化措施
CREATE INDEX idx_email on customer(email);
explain select sum(amount) from customer a,payment b where 1=1 and a.customer_id = b.customer_id and email = '[email protected]'\G