0. 雨后小故事
在遥远的“云顶镇”,有一个传说,说是在雨季,任何在雨中编写的代码都会变得无比强大。这里的程序员“流光”深信不疑,尤其是他开发的一款名为“瞬息商城”的应用,旨在提供超快的购物体验。
某天,一场突如其来的大雨倾盆而下,流光灵机一动,决定趁着这场雨优化他的“瞬息商城”。他冲到窗边,让雨水拍打在键盘上,一边听着雨声,一边敲击着代码,希望雨神能赋予他的程序神奇的力量。
然而,正当流光沉浸在代码的海洋中时,一个不小心,一杯水泼到了电脑上,导致电脑死机,刚刚写的代码全部丢失,包括一个至关重要的SQL查询。这个查询负责处理所有交易,它的缺失使得“瞬息商城”突然变成了“蜗牛商城”。
流光急得团团转,这时,他的好友,也是位程序员,建议他使用数据库性能分析工具,找出问题所在。流光听从建议,借助`EXPLAIN`和慢查询日志,很快定位到了问题,并且在雨停之前,修复了代码,甚至优化了查询,使得“瞬息商城”比雨前还要快!
当雨过天晴,太阳露出微笑,流光重启“瞬息商城”,应用如同脱胎换骨一般,不仅恢复了超快的性能,还意外地加入了雨天自动推荐雨伞和防水产品的功能,这让用户惊喜不已,也让“瞬息商城”在“云顶镇”赢得了前所未有的好评。
流光从这次经历中学到了,虽然传说中的魔法也许不存在,但掌握好代码优化和性能分析的技巧,就能在任何天气下创造奇迹。而“云顶镇”的居民,则永远记得那场改变“瞬息商城”命运的雨,以及流光如何在雨中书写传奇的故事。
虽然是故事,但也让我们初步了解到性能分析和优化的重要性。今天,我们就从四个方面来看看如何对mysql的性能进行分析。
1. SQL执行频率
SQL执行频率指的是特定类型的SQL语句在一定时间内被调用的次数。这有助于理解数据库的工作负载,比如你可以检查哪些类型的查询(如INSERT、UPDATE、DELETE或SELECT)最常被执行。
示例: 假设你想要查看全局的SQL执行频率,可以执行以下命令:
SHOW GLOBAL STATUS LIKE 'Com_%';
这会列出所有以Com_
开头的变量,它们代表了不同类型的SQL语句的执行次数。例如,Com_select
显示的是SELECT语句的执行次数。
2. 慢查询日志
慢查询日志是MySQL用来记录那些执行时间超过预设阈值(默认通常是10秒)的SQL语句的日志。这能帮助你找到性能瓶颈,特别是那些长时间运行的查询。
示例: 要启用慢查询日志,我们需要编辑MySQL配置文件( /etc/my.cnf 或 /etc/my.ini ),并添加或修改以下行:
# 开启慢查询日志
slow_query_log = 1
# 设置慢查询时间,超过此时间,会被标记为慢查询
long_query_time = 2
# 查看是否开启了慢查询
show variables like 'slow_query_log';
这里,long_query_time
定义了慢查询的阈值,即2秒。
3. Profiling
Profiling是一种更详细的性能分析方式,它可以显示查询执行的每个阶段所花费的时间,包括用户统计、查询时间、锁等待时间等。
示例: 首先,确保你的MySQL实例启用了Profiling功能:
SET profiling = 1;
查看profile是否已经开启:
SELECT @@have_profiling;
然后执行一个查询,之后使用以下命令来查看Profiling信息,即每一条SQL的耗时情况
SHOW PROFILES;
要获取特定查询的详细信息,可以使用:
SHOW PROFILE FOR QUERY query_id;
其中query_id
是你要分析的查询的ID。
4. EXPLAIN
EXPLAIN命令用于展示查询的执行计划,它显示了MySQL如何决定执行查询,包括使用哪些索引,以及数据是如何被读取的。
示例: 考虑以下SQL查询:
SELECT * FROM table_name WHERE column_name = 'value';
使用EXPLAIN来查看其执行计划:
EXPLAIN SELECT * FROM table_name WHERE column_name = 'value';
输出的结果可能看起来像这样:
1+----+-------------+-------+--------+---------------+---------+---------+------+------+----------+
2| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
3+----+-------------+-------+--------+---------------+---------+---------+------+------+----------+
4| 1 | SIMPLE | t1 | index | PRIMARY | PRIMARY | 4 | NULL | 1 | Using index |
5+----+-------------+-------+--------+---------------+---------+---------+------+------+----------+
下面我们来说说 explain 中每个字段的作用,理解这些字段有助于帮助我们理解查询的执行方式和优化点。
-
id
- 这个字段标识了查询的执行序列号,用于指示SQL语句的执行顺序。具有相同
id
的行可以并行执行,而不同的id
则可能表示子查询或不同的执行步骤。 - 较大的
id
值可能意味着更高的执行优先级,尤其是在涉及多个查询块的情况下。
- 这个字段标识了查询的执行序列号,用于指示SQL语句的执行顺序。具有相同
-
select_type
- 描述查询的类型,比如:
SIMPLE
: 单一的SELECT语句,没有子查询或联合。PRIMARY
: 包含子查询的主查询。SUBQUERY
: 子查询。DERIVED
: 导出表。UNION
: UNION语句的第一个SELECT。UNION RESULT
: UNION语句的结果。
- 描述查询的类型,比如:
-
table
- 显示当前执行计划涉及的具体表名。
-
type
- 描述了访问表的方式,这是非常重要的优化信息,常见的类型有:
ALL
: 全表扫描,效率最低。index
: 使用索引进行全索引扫描。range
: 使用索引扫描某个范围内的数据。ref
: 使用索引查找单行数据。eq_ref
: 对于每一行记录,只匹配表中的一行记录。const
: 常量表,只匹配一行。system
: 表只有一行(系统表)。NULL
: 不需要访问表或索引。
- 描述了访问表的方式,这是非常重要的优化信息,常见的类型有:
-
possible_keys
- 列出了可以应用于查询的索引列表,但并不一定被实际使用。
-
key
- 显示MySQL实际决定使用的键(索引)。如果为
NULL
,则没有使用索引。
- 显示MySQL实际决定使用的键(索引)。如果为
-
key_len
- 表示MySQL在索引中使用的字节数,这可以用来评估索引的效率。
-
ref
- 显示了索引列上被用于查找的列或常量,即连接匹配条件。
-
rows
- MySQL估计为了找到所需记录需要读取的行数,这个数字越小通常表示查询越高效。
-
Extra
- 包含了额外的信息,比如:
Using where
: 表示WHERE子句被使用。Using temporary
: 使用了临时表。Using filesort
: 数据需要进行排序。Using index
: 仅使用索引中的信息,不需要访问表本身。Impossible WHERE noticed after reading const tables
: 由于WHERE条件的存在,查询结果不可能。
- 包含了额外的信息,比如: