【MySQL】优化
慢查询日志
慢查询日志可以记录响应时间超过阈值的SQL语句,默认阈值为10秒。
该日志默认关闭,建议调优时打开,最终部署时关闭。
1. 检查是否打开了慢查询日志
|
|
2. 临时开启
|
|
MySQL服务器重启后会失效。
3. 永久开启
|
|
4. 查看慢查询阀值
|
|
或者:
|
|
5. 设置慢查询阀值
|
|
重新连接数据库后才生效。
6. 永久设置阀值
|
|
7. 查询超过阀值的sql个数
|
|
8. mysqldumpslow
可以使用mysqldumpslow工具查看慢查询日志,用法为:
|
|
查看服务器状态
可以使用如下命令查看服务器状态信息:
|
|
如果想查看SQL语句执行频率的统计信息,可以使用:
|
|
如果想查看InnoDB数据行的统计信息,可以使用:
|
|
排查低效率语句
排查低效率SQL语句,有以下两种方法:
-
慢查询
-
show processlist
执行计划字段分析
获取执行计划的语法为:EXPLAIN SQL语句。
1. id
select查询的序列号,表示查询中执行select子句的顺序。
id相同时,查询顺序从上往下。
id不同时,值越大,越先被执行。
2. select_type
SELECT的类型。
-
SIMPLE:简单查询,不包含子查询和UNION。 -
PRIMARY:包含子查询的SQL语句中的主查询(最外层)。 -
SUBQUERY:在SELECT子句或者WHERE子句中,包含的子查询。 -
DERIVED:衍生查询,使用到了临时表。FROM子句中的子查询会被标记为DERIVED,又或者UNION包含在FROM子句的子查询中,外层SELECT将会被标记为DRIVED。 -
UNION:UNION中的第二个或者之后的查询语句。 -
UNION RESULT:对UNION结果进行的查询。
3. table
查询的表。
4. type
表示表的访问类型。
连接类型的性能由好到坏,依次是:NULL、system、const、eq_ref、ref、fulltext、ref_or_null、index_merge、unique_subquery、index_subquery、range、index和all。
system,const很难遇见,最好能达到ref和range级别。
-
NULL不访问任何表,直接返回结果。
-
system(忽略)只有一条数据的系统表,或衍生表只有一条数据的主查询。
-
const仅仅能查到一条数据的
SQL,用于primary key或者unique索引。 -
eq_ref用于连接查询。
对于每个索引键的查询,返回匹配的唯一行数据,有且只有1个,不能为0。
常见于唯一索引和主键索引。
-
ref非唯一性索引查询,返回匹配的所有行。
-
range检索指定范围的行,需要使用一个索引。
-
index对索引表进行遍历。
-
all对数据表进行遍历。
5. Possible_keys
可能用到的索引。
6. key
实际用到的索引。
7. key_len
索引使用的字节数,其值为索引字段最大可能长度,越短越好。
可用于判断复合索引是否被完全使用。
对于utf8,一个字符占3个字节。如果索引字段可以为null,则会使用1个字节用于标识。如果索引字段为varchar,使用2个字节标识可变长度。
8. ref
用于指明当前表所参照的字段,注意跟type中的ref值区分开。
9. rows
实际通过索引查询到的数据个数。
10. extra
执行情况的额外说明。
-
using filesort需要额外进行一次排序,而不是使用索引的顺序,性能消耗大。常见于
order by语句中。示例1:
1explain select * from test where a1='' order by a2;小结:对于单索引,如果排序和查找是同一个字段,则不会出现
using filesort;如果排序和查找不是同一个字段,则会出现using filesort。示例2:(注意存在a1, a2, a3, a4四个字段)
1 2 3 4alter table test add index idx_a1_a2_a3 (a1, a2, a3); explain select * from test where a1='' order by a3; # using filesort explain select * from test where a2='' order by a3; # using filesort explain select * from test where a1='' order by a2;小结:对于复合索引,
where和order by按照复合索引的顺序使用,不要跨列或无序使用。 -
using temporary用到了临时表,性能损耗大。一般出现在
order by和group by语句中。示例:
1 2explain select * from test where a1 in (1, 2, 3) group by a1; explain select * from test where a1 in (1, 2, 3) group by a2; # using temporary -
using index性能较好,常见于索引覆盖。
只要使用到的列,全部都在索引中,就称为”索引覆盖“。
这时只需要从索引文件中获取数据,不需要读取数据文件,即不回表查询。
-
using where回表查询时,会出现
using where。 -
impossible wherewhere子句永远为false。 -
using join buffermysql引擎使用了连接缓存。 -
using index condition索引下推,先进行条件过滤再回表。
语句分析
1. profiles
-
查看是否支持
profiles。1SHOW VARIABLES LIKE "%have_profiling%";或者:
1SELECT @@have_profiling; -
查看
profiles开启状态。1SHOW VARIABLES LIKE "profiling";或者:
1SELECT @@profiling;返回的结果中,
OFF或者0表示关闭,ON或者1表示开启。 -
打开
profiles。1SET profiling=ON;或者:
1SET profiling=1;proflie开启之后,会记录所有查询语句所花的时间,但是不是很精确。 -
关闭
profiles。1SET profiling=OFF;或者:
1SET profiling=0; -
查看
profiles统计信息1SHOW profiles; -
查看某个查询的性能
1SHOW PROFILE [type...] FROM QUERY query_id;query_id可以通过上一个命令获取。type如果省略,则只显示时间消耗。常见的type参数有ALL、BLOCK IO、CPU、IPC等,表示需要进行分析的具体内容。
2. trace
MySQL5.6开始提供了针对SQL语句的TRACE,通过TRACE文件,可以知道执行计划的生成过程。
-
查看
trace的开启情况。1SHOW VARIABLES LIKE "optimizer_trace";或者:
1SELECT @@optimizer_trace; -
打开
trace。1SET optimizer_trace="enabled=on,one_line=off"; -
设置
trace能使用的内存大小。1SET optimizer_trace_max_mem_size=1048576; -
查看分析结果
1SELECT * FROM information_schema.optimizer_trace\G
3. 记录全局日志
记录开启之后的全部sql语句,建议只在调优和开发过程中打开。
-
查看状态
1 2SHOW VARIABLES LIKE '%general_log%'; SHOW VARIABLES LIKE "%log_output%"; -
开启,并将sql记录在表里
1 2SET GLOBAL general_log=1; SET GLOBAL log_output='table'; -
开启,并将sql记录在文件里
1 2 3SET GLOBAL general_log=1; SET GLOBAL log_output='file'; SET GLOBAL general_log_file='/tmp/general.log';
批量导入数据的优化
1. 批量插入数据的命令
|
|
对于数据文件中的每行数据,以,号来分隔每个字段。
2. 优化建议
-
按照主键顺序插入。
-
关闭对唯一性索引的校验:
1SET UNIQUE_CHECKS=0; -
关闭事务的自动提交:
1SET AUTOCOMMIT=0;
INSERT优化
-
如果对一张表插入多条数据,尽量将多条数据放在一个
INSERT语句中,能降低客户端和数据库的连接、关闭消耗,效率会比分开执行的INSERT语句快。 -
将多个插入放在一个事务中。
-
按照主键的顺序插入。
group by优化
group by除了会进行分组外,还会进行排序操作。如果分组时使用了聚合函数,则也会进行聚合函数的计算。
如果想避免排序造成的性能消耗,可以在group by子句之后,使用order by null来取消排序。
除了取消排序,还可以对分组字段建立索引。
子查询优化
使用子查询,可以一次性完成需要多个步骤才能完成的工作。
子查询的优化准则为,尽量使用连接查询代替子查询。
or优化
对于包含OR的查询语句,如果要使用到索引,则OR两侧的每个条件都必须用到索引。
优化方式除了增加索引外,还可以使用union替代or。
分页查询优化
-
在索引上完成排序分页操作,然后回数据表查询所需的其他字段。
-
将
limit查询转换成对某个位置的查询,适用于主键自增的表,即不能出现主键断层。如id > 10000 limit 10。 -
如果想优化
count(),可以新建一张表,记录总数。
人为控制索引
1. USE INDEX
使用USE INDEX(索引名),可以让MySQL只参考指定的索引,但不一定会使用。
2. IGNORE INDEX
可以使用IGNORE INDEX(索引名),来让MySQL忽略一个或多个索引。
3. FORCE INDEX
通过使用FORCE INDEX(索引名),可以强制要求MySQL使用指定的索引。
应用层面的优化
1. 使用连接池
对于数据库来说,建立连接的代价比较昂贵,因此,如果频繁的建立和关闭连接,会消耗较多资源。建立连接池,可以减少连接次数,提高访问性能。
2. 避免对数据进行重复查询
尽量一次性获取所需数据,减少无用的重复请求。
3. 增加缓存
可以在应用层和数据库之间,增加缓存层。查询数据时,直接访问缓存层,即可以提高查询速度,也可以降低数据库的压力。
4. 对查询进行分流
通过MySQL的主从复制,可以实现读写分离。
增删改操作由主结点执行,查询操作则分发给从结点,从而可以降低单台服务器的读写压力。
5. 分布式数据库架构
将数据分布在多台服务器,可以很好实现负载均衡,从而解决大数据量和高负载问题。
MySQL并发参数
1. max_connections
max_connections用于控制MySQL数据库的最大连接数,默认151,查看变量值的命令为:
|
|
或者:
|
|
注意,max_connections是全局变量。
当连接数达到最大值时,后续的连接请求可能会失败。查看失败的连接请求数的命令为:
|
|
设置最大连接数时,需要考虑多个因素的影响。如操作系统的内存大小、连接的负荷、cpu性能、期望的响应时间等。
2. back_log
如果MySQL的连接数达到max_connections,新来的请求会被放在堆栈中,back_log参数就是该堆栈能容纳的数量。
如果等待连接的数量超过back_log,新的连接请求就会报错。
3. thread_cache_size
MySQL数据库会缓存一些服务线程,当又客户端请求到来时,会将其中的服务线程分配给连接会话使用。
thread_cache_size用于控制该线程数量。
4. innodb_lock_wait_timeout
该参数,主要用于控制InnoDB事务等待行锁的时间。