SQL优化学习笔记(二)

   【深刻浅出mysql(第二版)18章学习笔记】
  了解SQL的执行频率以后,再继续了解如何分析SQL语句。分析SQL语句能够经过EXPLAIN、show profile、trace对SQL进行综合分析,其中EXPLAIN比较经常使用。

mysql

1 经过 EXPLAIN 分析低效SQL的执行计划

Explain能够定位SQL的执行问题,例如:
EXPLAIN SELECT sum(amount) from customer a, payment b WHERE 1=1 and a.customer_id = b.customer_id and email = 'JANE.BENNETT@sakilacutomer.org';
输出结果:
sql

各个列名的含义:
select_type : 表示select的类型,常见取值以下:json

SIMPLE :简单表,即不使用表链接或子查询;
PRIMARY: 主查询,即外层查询;
UNION : UNION 中的第二个或者后面的查询语句;
SUBQUERY : 子查询中的第一个select。性能

table:输出结果集的表;
type : 表示Mysql在表中找到找到所需行的方式,或者叫访问类型。常见类型以下:学习

ALL | index | range | ref | eq_ref | const/system | NULL
从左到右,性能由最差到最好。优化

possible_keys : 表示查询时可能使用到的索引;
key : 表示实际使用的索引;
key_len : 使用到索引字段的长度;
ref :
rows: 扫描行的数量;
Extra: 执行状况的说明和描述,包含不适合在其余列中显示可是对执行计划很是重要的额外信息。


详解 type 列:线程

(1)type=ALL

全表扫描,mysql遍历全表来找到匹配的行
EXPLAIN SELECT * FROM film WHERE rating > 9 ;
结果如图:


3d

(2)type=index

索引全扫描,mysql遍历整个索引来查询匹配的行
EXPLAIN SELECT title FROM film;
结果如图:
code

(3)type=range

索引范围扫描,常见于** <、 <=、 >、 >= 、between**等操做符。
EXPLAIN SELECT * FROM payment WHERE customer_id > 300 AND customer_id <=350;
结果如图:
orm

(4)type=ref

使用非惟一索引扫描或惟一索引的前缀扫描,返回匹配某个单独值的记录行
EXPLAIN SELECT * FROM payment WHERE customer_id =350;
结果如图:

索引 idx_fk_customer_id 是非惟一索引。

(5)type=eq_ref

与 ref 相似 ,区别在于使用的索引是惟一索引,对于每一个索引键值,表中只有一条记录匹配。即在多表链接中使用 primary key或者 unique index 做为关联条件。
EXPLAIN SELECT * FROM film a, film_text b WHERE a.film_id = b.film_id;
结果如图:

(6)type=const/system

单表中最多有一个匹配行,查询起来很是迅速,因此这个匹配行中的其余列的值能够被优化器在当前查询中看成常量来处理。例如,根据主键 primary key 或者惟一索引 unique index 进行的查询。

ALTER TABLE customer add UNIQUE INDEX uk_email (email);

EXPLAIN SELECT * FROM (SELECT * FROM customer WHERE email = 'AARON.SELBY@sakilacustomer.org') a;

结果如图:



经过惟一索引 uk_email 访问的时候,类型 type=const;而仅有一条记录的表中检索时,类型 type = system。

(7)type=NULL

mysql 不用访问表或者索引,直接就能获得结果。
EXPLAIN SELECT 1 FROM DUAL where 1;
结果如图:



2)经过 show profile 分析SQL
【主要查看SQL语句执行的时候,时间耗费在什么地方】
首先查询当前mysql是否支持 profile (profile 能够帮助了解SQL执行的过程)
SELECT @@have_profiling;


若是profiling是关闭的,能够经过set语句在Session级别开启profiling:

SELECT @@profiling;

SET profiling=1;

关于profile的做用:
第一步:执行一个count(*)查询
SELECT COUNT(*) FROM payment;

第二步:查看当前SQL的query id
show PROFILES;

第三步:经过 show profile for query 语句查看执行过程当中线程的每一个状态和消耗的时间
show PROFILE for QUERY 167;

注:

  • [ ]Sending data 状态表示mysql线程开始访问数据并把结果返回给客户端,而不单单是返回结果给客户端。因为在Sending data状态下,mysql线程须要作大量的磁盘读取操做,因此是整个查询过程当中耗时最长的状态。

  • [ ]show profile for query 语句也支持选择all、 CPU、block io 、 context switch、page faults 等明细类型来查看mysql在使用什么资源上耗费了太高的时间。例如,查看cpu的耗费时间:

3) 经过trace分析优化器如何选择执行计划

首先打开trace ,设置格式为JSON,设置trace最大可以使用的内存大小。

SET OPTIMIZER_TRACE="enabled=on",end_markers_in_json=on;

SET optimizer_trace_max_mem_size=1000000;

执行示例:

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;
// 如下语句会输出一个格式为json的跟踪文件
SELECT * FROM information_schema.OPTIMIZER_TRACE;
相关文章
相关标签/搜索