常见 MySQL 的慢查询优化方式
慢查询日志概念
MySQL
默认情况下,Mysql
慢查询日志相关参数
MySQL 慢查询的相关参数解释:
- slow_query_log :是否开启慢查询日志,1
表示开启,0 表示关闭。 - log-slow-queries :旧版(5.6
以下版本)MySQL 数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件 host_name-slow.log - slow-query-log-file:新版(5.6
及以上版本)MySQL 数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件 host_name-slow.log - long_query_time :慢查询阈值,当查询时间多于设定的阈值时,记录日志。
- log_queries_not_using_indexes:未使用索引的查询也被记录到慢查询日志中(可选项)。
- log_output:日志存储方式。log_output=’FILE’
表示将日志存入文件,默认值是’FILE’。log_output=’TABLE’ 表示将日志存入数据库,这样日志信息就会被写入到 mysql.slow_log 表中。MySQL 数据库支持同时两种日志存储方式,配置的时候以逗号隔开即可,如:log_output=’FILE,TABLE’。日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源,因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件。
一,第一步.
方式一:
修改配置文件 在 my.ini 增加几行: 主要是慢查询的定义时间,以及慢查询
方法二:通过
二,分析慢查询日志
直接分析
例如:执行
EXPLAIN SELECT * FROM res_user ORDER BYmodifiedtime LIMIT 0,1000
table | type | possible_keys | key |key_len | ref | rows | Extra
EXPLAIN
- table 显示这一行的数据是关于哪张表的
- type 这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为
const、eq_reg、ref、range、indexhe 和 ALL - rows 显示需要扫描行数
- key 使用的索引
三,常见的慢查询优化
(1)索引没起作用的情况
- 使用
LIKE 关键字的查询语句
在使用LIKE 关键字进行查询的查询语句中,如果匹配字符串的第一个字符为 “%”,索引不会起作用。只有 “%” 不在第一个位置索引才会起作用。 - 使用多列索引的查询语句
MySQL可以为多个字段创建索引。一个索引最多可以包括 16 个字段。对于多列索引,只有查询条件使用了这些字段中的第一个字段时,索引才会被使用。
(2)优化数据库结构
合理的数据库结构不仅可以使数据库占用更小的磁盘空间,而且能够使查询速度更快。数据库结构的设计,需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。
- 将字段很多的表分解成多个表
对于字段比较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。 - 增加中间表
对于需要经常联合查询的表,可以建立中间表以提高查询效率。通过建立中间表,把需要经常联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询,以此来提高查询效率。
(3)分解关联查询
将一个大的查询分解为多个小查询是很有必要的。
很多高性能的应用都会对关联查询进行分解,就是可以对每一个表进行一次单表查询,然后将查询结果在应用程序中进行关联,很多场景下这样会更高效,例如:
1 |
|
分解为:
1 |
|
(4)优化
在系统中需要分页的操作通常会使用
一个非常令人头疼问题就是当偏移量非常大的时候,例如可能是
优化此类查询的一个最简单的方法是尽可能的使用索引覆盖扫描,而不是查询所有的列。然后根据需要做一次关联操作再返回所需的列。对于偏移量很大的时候这样做的效率会得到很大提升。
对于下面的查询:
select id,title from collect limit 90000,10;
该语句存在的最大问题在于
如果表非常大,且筛选字段没有合适的索引,且
方法一:虑筛选字段(title)上加索引
title
方法二:先查询出主键select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10;
原理:先查询出
方法三:“关延迟联”
select news.id, news.description from news inner join (select id from news order by title limit 50000,5) as myNew using(id);
这里的
方法四:建立复合索引 acct_idselect * from acct_trans_log WHERE acct_id = 3095 order by create_time desc limit 0,10