您的位置:首页 > 数据库

SQL语句优化

2015-06-24 16:47 441 查看
1. 数据准备:

sakila数据库 mysql5.5 http://dev.mysql.com/doc/index-other.html

表结构信息: http://dev.mysql.com/doc/sakila/en/sakila-installation.html

2. mysql慢日志开启方式

利用慢查询日志对效率问题进行监控 -- 用来发现有问题的日志

1. 查询是否开启对未设置索引的查询开启慢查询

show variables like 'log_queries_not_using_indexes';
set global log_queries_not_using_indexes = on;

show variables like 'long_query_time';
set long_query_time = 0; (单位:秒)

show variables like 'slow_query_log'

set global slow_query_log = on;

show variables like 'slow_query_log_file';
set global slow_query_log_file = '/home/log'

实际应用过程中,使用命令行上面的配置没有生效,不知道为什么。最后修改my.ini,重启mysql之后,才生效。

慢查询日志的存储格式

select * from payment;

# Time: 2015-06-24T06:52:58.315864Z

# User@Host: root[root] @ localhost [::1] Id: 1

# Query_time: 0.076355 Lock_time: 0.061227 Rows_sent: 1 Rows_examined: 0

SET timestamp=4294967113;

包括: 主机信息、SQL执行信息、SQL执行时间、SQL内容

如何分析日志?

分析工具:
1. mysqldumpslow

mysqldumpslow -h

mysqldumpslow -t 3 日志路径 | more (前3个最慢的查询)

2.pt-query-digest工具

pt-query-digest 慢查询日志 > slow_log.report //输出到日志
//输出到数据库
pt-query-digest mysql-slow.log -review \
h=127.0.0.1,D=test,p=root,P=3306,u=root,t=query_review\
--create-reviewtable \
--review-history t = hostname_slow

如何发现问题?

1.查询次数多且每次查询占用时间长
2.I/O大的SQL rows examine参数
3. 未命中索引的SQL row examine 和 Row send参数

如何分析查询?

使用explain查询SQL的执行计划



参数含义:
table --- 从哪个表查询
type --- 从好到坏const(主键,唯一索引), eq_reg(范围查找), ref(连接查询), range(索引范围), index(索引扫描), all(表扫描)
possible_keys --- 可以用到的索引
key: 实际使用的索引
ken_len:索引长度,在不影响精度情况下,索引长度越少越好
ref: 索引的哪一列被使用
rows: mysql认为必须检查的用来返回请求数据的行数
Using filesort: 看到这个的时候,查询就需要优化。Mysql需要额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行指针排序。
Using temporary: 需要优化。Mysql需要创建一个临时表来存储数据。通常发生在对不同的列集进行ORDER BY,而不是GROUP BY

优化MAX()

explain max(payment_date) from payment; //扫描行数较多

create index idx_paydate on payment(payment_date); //覆盖索引,按顺序排列,只需取最后一行的索引数据

优化COUNT()

count(*) 与 count(id) 区别: count(id) 对于NULL值不会计数。

子查询优化--一般优化成join方式,但需要注意是否存在一对多关系。
如果存在一对多关系的化,子查询仍然会返回正确的记录,但是join方式会返回多条记录,会有冗余,所以要添加distinct

select * from t where t.id in(select t1.tid from t1); --> select t.id from t join t1 on t.id = t1.tid;

GROUP BY

explain select actor.first_name, actor.last_name,count(*) from sakila.film_actor inner join sakila.actor using(actor_id) group by film_actor.actor_id\G;

改写为:

explain select actor.first_name, actor.last_name, c.cnt from sakila.actor inner join (select actor_id, count(*) as cnt from sakila.film_actor group by actor_id) as c using(actor_id)\G;

LIMIT
limit常用于分页处理,伴随order by 从句使用。
explain select film_id, description from film order by title limit 50,5\G;

优化步骤1:使用有索引的列或主键进行order by
优化步骤2:记录上次返回的主键,在下次查询时候使用主键过滤。(注意:保证主键连续增长)

思想:避免数据量大时候扫描过多的记录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: