从优化效果及成本考虑,可以依次从以下几个方面考虑:
$ curl http://dev.mysql.com/doc/index-other.html
$ wget three files: sakilaschema.sql, sakila-data.sql, and sakila.mwb
$ mysql -uxxx -p
mysql> SOURCE xxx/sakila-schema.sql;
mysql> SOURCE xxx/sakila-data.sql;
mysql> USE sakila;
mysql> SHOW TABLES;
mysql> SELECT COUNT(*) FROM film;
mysql> SELECT COUNT(*) FROM film_text;
发现有问题的sql:
## 使用mysql慢查询日志对有效率问题的sql进行监控
# 查看及设置慢查询日志存储的日志文件的位置在哪里(默认的慢查询日志在 /var/lib/mysql/xxx-slow.log)
mysql> show variables like '%query_log%';
mysql> set global slow_query_log_file='/home/ubuntu/sql_log/mysql_slow.log';
# 设置开启慢查询日志
mysql> set global slow_query_log=on;
# 设置将没有使用索引的sql记录到慢查询日志中
mysql> set global log_queries_not_using_indexes=on;
# 设置将超过多少秒的sql记录到慢查询日志中
mysql> set global long_query_time=1;
## 慢查询日志的格式
$ sudo tail -f /var/lib/mysql/xxx-slow.log
----------------
# Time: 180602 9:49:17 --执行sql的时间
# User@Host: root[root] @ localhost [] Id:11 --执行sql的主机信息
# Query_time: 0.000125 Lock_time: 0.000060 Rows_sent: 2 Rows_examined: 2 --sql执行信息
SET timestamp=1527904157; --sql执行时间的时间戳
select * from store limit 10; --sql的内容
## 慢查日志的分析工具
# 1. mysql自带的官方工具 mysqldumpslow [--help]
# 分析得出前3条慢查询日志
$ sudo mysqldumpslow -t 3 /var/lib/mysql/xxx-slow.log
# 2. pt-query-digest(提供了更为详细的慢查询日志信息)
# 安装
$ wget percona.com/get/pt-query-digest
$ sudo chmod u+x pt-query-digest
$ sudo chown root:root pt-query-digest
$ sudo mv /xxx/pt-query-digest /usr/bin/
# 使用
$ sudo pt-query-digest /var/lib/mysql/xxx-slow.log
$ sudo pt-query-digest /var/lib/mysql/xxx-slow.log -review \
h=127.0.0.1,P=3306,D=test,u=root,p=xxx,t=query_review \
--create-reviewtable \
--review-history t=hostname_show
## 如何通过慢查询日志发现有问题的sql?
# 1. 查询次数多且每次查询占用时间长的sql(通常为pt-query-digest分析的前几个查询语句)
# 2. IO大的sql(注意pt-query-digest分析中的 Rows examine 项,表示扫描了多少行)
# 3. 未命中索引的sql(注意pt-query-digest分析中的 Rows examine 和 Rows Send 的对比)
# 如果 扫描的行数 远远大于 发送回来的行数,就表示索引的命中率不是很高
找到了具体慢sql之后,如何对其进行优化?
# 使用 explain 分析慢sql
mysql> explain xxxsql;
# 输出结果字段
table:表名
type:连接的类型,从好到差的连接类型依次为 const、eq_reg、ref、range、index、ALL
const:主键、索引
eq_reg:主键、索引的范围查找
ref:连接的查找(join)
range:索引的范围查找
index:索引的扫描
All:表扫描
possible_keys:可能用到的索引,如果为空则表示没有可能的索引
key:实际使用的索引,如果为空则表示没有使用索引
key_len:使用的索引的长度,在不损失精确性的前提下长度越短越好
ref:显示索引的那一列被使用了,如果可能的话最好是一个常数
rows:mysql认为必须检查的返回请求数据的行数(一般为需要扫描的行数)
extra:需要注意的有这两个枚举值 Using filesort 和 Using temporary,这两个值出现之后,通常需要优化
Using filesort 表示mysql需要进行额外的步骤对返回的行进行排序,它根据l连接的类型以及存储排序键值
和匹配条件的全部行的行指针来排序全部行;
Using temporary 表示mysql需要创建一张临时表来存储结果,通常发生在对不同的列集进行order by上,
而不是group by上。
如何查找数据库重复冗余索引?
## 使用 pt-duplicate-key-checker 工具
$ pt-duplicate-key-checker -h 127.0.0.1 -uroot -p 'xxxxxx'
## 建表选择合适的数据类型
# 1. 使用可以存储下你的数据的最小数据类型
# 2. 使用简单的数据类型,int要比varchar类型在mysql处理上简单
# 3. 尽可能的使用 not null 定义字段
# 4. 尽量少用 text 类型,非用不可时最好考虑分表
## 示例
# 使用 int 存储日期时间
create table xxx(
id int primary key auto_increment,
updatetime int
);
insert into xxx(updatetime) values(unix_timestamp('2017-08-05 12:12:23'));
select from_unixtime(updatetime) from xxx;
# 使用 bigint 存储ip地址
create table xxx2(
id int primary key auto_increment,
ip bigint
)
insert into xxx2(ip) values(inet_aton('192.168.0.23'));
select inet_ntoa(ip) from xxx2;