数据库
首页 > 数据库> > 35 张图带你 MySQL 调优(转)

35 张图带你 MySQL 调优(转)

作者:互联网

一般传统互联网公司很少接触到 SQL 优化问题,其原因是数据量小,大部分厂商的数据库性能能够满足日常的业务需求,所以不需要进行 SQL 优化。但是随着应用程序的不断变大,数据量的激增,数据库自身的性能跟不上了,此时就需要从 SQL 自身角度来进行优化,这也是我们这篇文章所讨论的。

1 SQL 优化步骤

当面对一个需要优化的 SQL 时,我们有哪几种排查思路呢?

1.1 通过 show status 命令了解 SQL 执行次数

首先,我们可以使用 show status 命令查看服务器状态信息。show status 命令会显示每个服务器变量 variable_name 和 value,状态变量是只读的。如果使用 SQL 命令,可以使用 like 或者 where 条件来限制结果。like 可以对变量名做标准模式匹配。

图片

图我没有截全,下面还有很多变量,读者可以自己尝试一下。也可以在操作系统上使用 mysqladmin extended-status 命令来获取这些消息。

但是我执行 mysqladmin extended-status 后,出现这个错误。

图片

应该是我没有输入密码的原因,使用 mysqladmin -P3306 -uroot -p -h127.0.0.1 -r -i 1 extended-status 后,问题解决。

这里需要注意一下 show status 命令中可以添加统计结果的级别,这个级别有两个:

如果不指定统计结果级别的话,默认使用 session 级别

对于 show status 查询出来的统计结果,有两类参数需要注意下,一类是以 Com_ 为开头的参数,一类是以 Innodb_ 为开头的参数。

下面是 Com_ 为开头的参数,参数很多,我同样没有截全。

图片

Com_xxx 表示的是每个 xxx 语句执行的次数,我们通常关心的是 select 、insert 、update、delete 语句的执行次数,即:

以 Innodb_ 为开头的参数主要有:

通过上面这些参数执行结果的统计,我们能够大致了解到当前数据库是以更新(包括插入、删除)为主,还是以查询为主。

除此之外,还有一些其他参数用于了解数据库的基本情况。

1.2 定位执行效率较低的 SQL

定位执行效率比较慢的 SQL 语句,一般有两种方式:

MySQL 中提供了一个慢查询的日志记录功能,可以把查询 SQL 语句时间大于多少秒的语句写入慢查询日志,日常维护中可以通过慢查询日志的记录信息快速准确地判断问题所在。用 --log-slow-queries 选项启动时,mysqld 会写一个包含所有执行时间超过 long_query_time 秒的 SQL 语句的日志文件,通过查看这个日志文件定位效率较低的 SQL 。

比如我们可以在 my.cnf 中添加如下代码,然后退出重启 MySQL。

log-slow-queries = /tmp/mysql-slow.loglong_query_time = 2

通常我们设置最长的查询时间是 2 秒,表示查询时间超过 2 秒就记录了,通常情况下 2 秒就够了,然而对于很多 WEB 应用来说,2 秒时间还是比较长的。

也可以通过命令来开启。

我们先查询 MySQL 慢查询日志是否开启:

show variables like "%slow%";

图片

启用慢查询日志:

set global slow_query_log='ON';

图片

然后再次查询慢查询是否开启:

图片

如图所示,我们已经开启了慢查询日志。

慢查询日志会在查询结束以后才记录,所以在应用反应执行效率出现问题的时候慢查询日志并不能定位问题,此时应该使用 show processlist 命令查看当前 MySQL 正在进行的线程。包括线程的状态、是否锁表等,可以实时的查看 SQL 执行情况。同样,使用 mysqladmin processlist 语句也能得到此信息。

图片

下面就来解释一下各个字段对应的概念:

State 列非常重要,这里面涉及线程的状态、是否锁表等选项,可以实时的查看 SQL 的执行情况,同时对一些锁表进行优化。

1.3 通过 EXPLAIN 命令分析 SQL 的执行计划

通过以上步骤查询到效率低的 SQL 语句后,可以通过 EXPLAIN 或者 DESC 命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。

比如我们使用下面这条 SQL 语句来分析一下执行计划:

explain select * from test1;

图片

上表中涉及内容如下:

图片

PRIMARY ,查询中最外层的 SELECT(如两表做 UNION 或者存在子查询的外层的表操作为 PRIMARY,内层的操作为 UNION),比如下面这段子查询。

图片

UNION,在 UNION 操作中,查询中处于内层的 SELECT(内层的 SELECT 语句与外层的 SELECT 语句没有依赖关系时)。

SUBQUERY:子查询中首个SELECT(如果有多个子查询存在),如我们上面的查询语句,子查询第一个是 sr(sys_role)表,所以它的 select_type 是 SUBQUERY。

type 这个字段会牵扯到连接的性能,它的不同类型的性能由好到差分别是:

上面就是 type 内容的大致解释,关于 type 我们经常会在 SQL 调优的环节使用 explain 分析其类型,然后改进查询方式,越靠近 system 其查询效率越高,越靠近 all 其查询效率越低。

图片

通过上面的分析,我们可以大致确定 SQL 效率低的原因。一种非常有效的提升 SQL 查询效率的方式就是使用索引,接下来我会讲解一下如何使用索引提高查询效率。

2 使用索引提高查询效率

索引是数据库优化中最常用也是最重要的手段,通过使用不同的索引可以解决大多数 SQL 性能问题,也是面试经常会问到的优化方式,围绕着索引,面试官能让你造出火箭来,所以总结一点就是索引非常非常重要。不只是使用,你还要懂其原理。

2.1 索引介绍

索引的目的就是用于快速查找某一列的数据,对相关数据列使用索引能够大大提高查询操作的性能。不使用索引,MySQL 必须从第一条记录开始读完整个表,直到找出相关的行,表越大查询数据所花费的时间就越多。如果表中查询的列有索引,MySQL 能够快速到达一个位置去搜索数据文件,而不必查看所有数据,那么将会节省很大一部分时间。

2.2 索引分类

先来了解一下索引都有哪些分类:

从逻辑上来对 MySQL 进行分类,主要分为下面这几种。

create index normal_index on cxuan003(id);

 

图片

 


删除方式:

drop index normal_index on cxuan003;

 

图片

create unique index normal_index on cxuan003(id);

 

图片

CREATE TABLE table (       id int(11) NOT NULL AUTO_INCREMENT ,       title char(255) NOT NULL ,       PRIMARY KEY (id))

 

图片

CREATE TABLE table (  id int(11) NOT NULL AUTO_INCREMENT,  title char(255) CHARACTER NOT NULL,  content text CHARACTER NULL,  time int(10) NULL DEFAULT NULL,  PRIMARY KEY (id), FULLTEXT (content));

CREATE FULLTEXT INDEX index_content ON article(content)

2.3 索引使用

索引可以在创建表的时候进行创建,也可以单独创建,下面我们采用单独创建的方式,我们在 cxuan004 上创建前缀索引:

图片

我们使用 explain 进行分析,可以看到 cxuan004 使用索引的情况:

图片

如果不想使用索引,可以删除索引,索引的删除语法是:

图片

2.4 索引使用细则

我们在 cxuan005 上根据 id 和 hash 创建一个复合索引,如下所示:

create index id_hash_index on cxuan005(id,hash);

图片

然后根据 id 进行执行计划的分析:

explain select * from cxuan005 where id = '333';

图片

可以发现,即使 where 条件中使用的不是复合索引(Id 、hash),索引仍然能够使用,这就是索引的前缀特性。但是如果只按照 hash 进行查询的话,索引就不会用到。

explain select * from cxuan005 where hash='8fd1f12575f6b39ee7c6d704eb54b353';

图片

如果 where 条件使用了 like 查询,并且 % 不在第一个字符,索引才可能被使用。

对于复合索引来说,只能使用 id 进行 like 查询,因为 hash 列不管怎么查询都不会走索引。

explain select * from cxuan005 where id like '%1';

图片

可以看到,如果第一个字符是 % ,则没有使用索引。

explain select * from cxuan005 where id like '1%';

图片

如果使用了 % 号,就会触发索引。如果列名是索引的话,那么对列名进行 NULL 查询,将会触发索引。

explain select * from cxuan005 where id is null;

图片

还有一些情况是存在索引但是 MySQL 并不会使用的情况。

explain select * from cxuan005 where id = 111 and info = 'cxuan';

图片

explain select * from cxuan005 where hash = '8fd1f12575f6b39ee7c6d704eb54b353';

图片

explain select * from cxuan005 where id + '111' = '666';

图片

explain select * from cxuan005 where concat(id,'111') = '666';

图片

关于设置索引但是索引没有生效的场景还有很多,这个需要小伙伴们工作中不断总结和完善,不过我上面总结的这些索引失效的情景,能够覆盖大多数索引失效的场景了。

2.5 查看索引的使用情况

在 MySQL 索引的使用过程中,有一个 Handler_read_key 值,这个值表示了某一行被索引值读的次数。Handler_read_key 的值比较低的话,则表明增加索引得到的性能改善不是很理想,可能索引使用的频率不高。

还有一个值是 Handler_read_rnd_next,这个值高则意味着查询运行效率不高,应该建立索引来进行抢救。这个值的含义是在数据文件中读下一行的请求数。如果正在进行大量的表扫描,Handler_read_rnd_next 的值比较高,就说明表索引不正确或写入的查询没有利用索引。

图片

3 MySQL 分析表、检查表和优化表

对于大多数开发者来说,他们更倾向于解决简单 SQL的优化,而复杂 SQL 的优化交给了公司的 DBA 来做。

下面就从普通程序员的角度和你聊几个简单的优化方式。

3.1 MySQL 分析表

分析表用于分析和存储表的关键字分布,分析的结果可以使得系统得到准确的统计信息,使得 SQL 生成正确的执行计划。如果用于感觉实际执行计划与预期不符,可以执行分析表来解决问题,分析表语法如下:

analyze table cxuan005;

图片

分析结果涉及到的字段属性如下:

对表的定期分析可以改善性能,应该成为日常工作的一部分。因为通过更新表的索引信息对表进行分析,可改善数据库性能。

3.2 MySQL 检查表

数据库经常可能遇到错误,比如数据写入磁盘时发生错误,或是索引没有同步更新,或是数据库未关闭 MySQL 就停止了。遇到这些情况,数据就可能发生错误: Incorrect key file for table: ' '. Try to repair it. 此时,我们可以使用 Check Table 语句来检查表及其对应的索引。

check table cxuan005;

图片

检查表的主要目的就是检查一个或者多个表是否有错误。Check Table 对 MyISAM 和 InnoDB 表有作用。Check Table 也可以检查视图的错误。

3.3 MySQL 优化表

MySQL 优化表适用于删除了大量的表数据,或者对包含 VARCHAR、BLOB 或则 TEXT 命令进行大量修改的情况。MySQL 优化表可以将大量的空间碎片进行合并,消除由于删除或者更新造成的空间浪费情况。它的命令如下:

optimize table cxuan005;

图片

我的存储引擎是 InnoDB 引擎,但是从图可以知道,InnoDB 不支持使用 optimize 优化,建议使用 recreate + analyze 进行优化。optimize 命令只对 MyISAM 、BDB 表起作用

标签:使用,35,查询,索引,调优,SQL,MySQL,张图,id
来源: https://blog.csdn.net/haiquanquan123456/article/details/121019832