如何发现有问题的 SQL?答案是使用 MySQL 慢查询日志对有效率问题的 SQL 进行监控,执行命令如下:
# 查看是否开启慢查询日志
show variables like "slow_query_log";
# 查看是否设置了把没有索引的记录到慢查询日志
show variables like "log_queries_not_using_indexes";
# 查看是否设置慢查询的 SQL 执行时间
show variables like "long_query_time";
# 查看慢查询日志记录位置
show variables like "slow_query_log_file";
# 开启慢查询日志
set global slow_query_log=on
# 设置没有索引的记录到慢查询日志
set global log_queries_not_using_indexes=on
# 设置到慢查询日志的 SQL 执行时间(1 代表 1 秒)
set global long_query_time=1
# 查看慢查询日志(在 Linux 终端下执行)
tail -50 /usr/local/var/mysql/luyiyuandeMacBook-Pro-slow.log;
SELECT
title ,
release_year ,
LENGTH
FROM
film
WHERE
film_id IN(
SELECT
film_id
FROM
film_actor
WHERE
actor_id IN(
SELECT
actor_id
FROM
actor
WHERE
first_name = 'sandra'
)
)
group by 可能会出现临时表、文件排序等,影响效率。可以通过关联的子查询,来避免产生临时表和文件排序,可以节省 IO。
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;
执行结果如下:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: actor
partitions: NULL
type: ALL
possible_keys: PRIMARY
key: NULL
key_len: NULL
ref: NULL
rows: 200
filtered: 100.00
Extra: Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: film_actor
partitions: NULL
type: ref
possible_keys: PRIMARY,idx_fk_film_id
key: PRIMARY
key_len: 2
ref: sakila.actor.actor_id
rows: 27
filtered: 100.00
Extra: Using index
2 rows in set, 1 warning (0.01 sec)
group by 查询优化后:
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);
CREATE TABLE test(
id INT NOT NULL PRIMARY KEY ,
NAME VARCHAR(10) NOT NULL ,
title VARCHAR(50) NOT NULL ,
KEY(NAME , id)
) ENGINE = INNODB;
查找重复及冗余索引的 SQL 语句如下:
USE information_schema;
SELECT
a.TABLE_SCHEMA AS '数据名' ,
a.table_name AS '表名' ,
a.index_name AS '索引1' ,
b.INDEX_NAME AS '索引2' ,
a.COLUMN_NAME AS '重复列名'
FROM
STATISTICS a
JOIN STATISTICS b ON a.TABLE_SCHEMA = b.TABLE_SCHEMA
AND a.TABLE_NAME = b.table_name
AND a.SEQ_IN_INDEX = b.SEQ_IN_INDEX
AND a.COLUMN_NAME = b.COLUMN_NAME
WHERE
a.SEQ_IN_INDEX = 1
AND a.INDEX_NAME <> b.INDEX_NAME
目录
数据准备
打开链接下载数据
打开终端,执行以下命令
数据库结构优化
选择合适的数据类型
数据库表的范式化优化与反范式化优化
为了避免冗余数据,可以根据数据库表设计第三范式对数据的储存进行优化设计;也可以为了提高性能,采用数据库表设计反范式化设计去冗余数据,使得数据库的查询更加的快速。
数据库表垂直拆分
垂直拆分,就是把原来一个有很多列的表拆分成多个表,这解决了表的宽度问题。通常垂直拆分就可以按以下原则进行:
数据库表垂直拆分实践
TODO
数据库表水平拆分
当单表的数据量过大,导致增删查改等操作过慢,这时候需要对表进行水平拆分。水平拆分的表,每一张表的结构都是完全一致的。
常用的水平拆分方法为:
挑战:
数据库表水平拆分实践
TODO
MySQL 慢查询日志
慢查询日志配置
如何发现有问题的 SQL?答案是使用 MySQL 慢查询日志对有效率问题的 SQL 进行监控,执行命令如下:
慢查询日志所存内容
慢查询日志分析工具
mysqldumpslow /usr/local/var/mysql/luyiyuandeMacBook-Pro-slow.log;
brew install percona-toolkit
pt-query-digest /usr/local/var/mysql/luyiyuandeMacBook-Pro-slow.log | more;
慢查询日志判断问题 SQL 的依据
EXPLAIN 分析 SQL 的执行计划
使用 EXPLAIN 分析 SQL
使用 EXPLAIN 分析 SQL 后各个参数含义如下:
执行 EXPLAIN 分析 SQL 返回结果如下:
SQL 优化
MAX() 优化
分析 SQL 语句:使用 MAX() 方法查询最后一笔交易的时间
执行结果如下:
如果数据表的数据非常大,查询频率又非常高,那么服务器的 IO 消耗也会非常高,所以这条 SQL 语句需要优化。可以通过建立索引进行优化。执行代码如下:
然后再分析 SQL 语句,执行结果如下:
经过优化之后,由于索引是按顺序排列的,MySQL 不需要查询表中的数据,而是通过查询索引最后的一个数据,就可以得知执行结果了。而且这个时候,不管表的数据量多大,查询 MAX() 所需要的时间都是基本固定的,这样就尽可能地减少了 IO 操作。
COUNT() 优化
分析 SQL 语句:使用 COUNT() 函数在一条 SQL 中同时查出 2006 年和 2007 年电影的数量
count(*) 包含空值,count(id) 不包含空值。上述语句就是优化 Count() 函数取值
子查询优化
分析 SQL 语句:查询 sandra 出演的所有影片
通常情况下,需要把子查询优化为 join 查询,但在优化时要注意关联键是否有一对多的关系,要注意重复数据。
GROUP BY 优化
group by 可能会出现临时表、文件排序等,影响效率。可以通过关联的子查询,来避免产生临时表和文件排序,可以节省 IO。
group by 查询优化前:
执行结果如下:
group by 查询优化后:
执行结果如下:
LIMIT 优化
LIMIT 常用于分页处理,时常会伴随 ORDER BY 从句使用,因此大多时候会使用 Filesorts ,这样会造成大量的 IO 问题
优化步骤1:使用有索引的列或主键进行 Order By 操作 优化步骤2:记录上次返回的主键,在下次查询时使用主键过滤(保证主键是自增且有索引)
索引优化
为合适的列建立索引
例如:
上述 SQL 语句,是
index(staff_id,customer_id)
合理,还是index(customer_id,staff_id)
合理。执行语句如下:由于 customer_id 的离散度更大,所以应该使用
index(customer_id,staff_id)
找到重复和冗余的索引
之所以要找到重复和冗余的索引,是因为过多的索引不但影响写入,而且影响查询,索引越多,分析越慢。那么为何重复索引、冗余索引?概念如下:
重复索引是指相同的列以相同的顺序建立的同类型的索引,如下表中 primary key 和 ID 列上的索引就是重复索引,例子如下:
UNIQUE(ID)
和PRIMARY KEY
重复了。 冗余索引是指多个索引的前缀列相同,或是在联合索引中包含了主键的索引,例子如下:查找重复及冗余索引的 SQL 语句如下:
也可以使用工具
pt-duplicate-key-checker
检查重复索引和冗余索引,使用例如:执行结果如下:
删除不用的索引
目前 MySQL 中还没有记录索引的使用情况,但是在 PerconMySQL 和 MariaDB 中可以通过 INDEX_STATISTICS 表来查看哪些索引未使用,但在 MySQL 中目前只能通过慢查询日志配合共组
pt-index-usage
来进行索引使用情况的分析。系统配置优化
数据库系统配置优化
数据库是基于操作系统的,目前大多数 MySQL 都是安装在Linux 系统之上,所以对于操作系统的一些参数配置也会影响到 MySQL 的性能,下面列举一些常用到的系统配置。
网络方面的配置,要修改文件
/etc/sysctl.conf
打开文件数的限制,可以使用 ulimit -a 查看目录的各项限制,可以修改文件
/etc/security/limits.conf
,增加以下内容以修改打开文件数量的限制除此之外最好在 MySQL 服务器上关闭 iptables,selinux 等防火墙软件。
MySQL 配置文件
MySQL 可以通过启动时指定配置参数和使用配置文件两种方法进行配置,在一般情况下,配置文件位于
/etc/my.cnf
或是/etc/mysql/my.cnf
,MySQL 查询配置文件的顺序是可以通过以下方法过的常用参数说明
存储引擎及版本的选择
请选择 MySQL InnoDB 存储引擎及 MySQL 5.5+ 的版本,原因如下:
第三方配置工具使用
percona:https://tools.percona.com/
服务器硬件优化
MySQL 服务器集群
TODO