数据库
首页 > 数据库> > 系列学习 MySQL 之第 6 篇 —— MySQL 性能调优篇

系列学习 MySQL 之第 6 篇 —— MySQL 性能调优篇

作者:互联网

 

应用系统正式上线后,随着生产数据量的急剧增长,数据库开始显露性能问题,对生产的影响也越来越大,因此我们必须对它们进行优化。如何优化 MySQL 数据库,比如优化查询速度、优化更新速度和优化 MySQL 服务器等。在讲解 MySQL 性能调优前,我们先了解 MySQL 的日志和分类。参考:http://c.biancheng.net/mysql/

MySQL 中有 4 种日志文件:

在 MySQL 所支持的日志文件里,除了二进制日志文件外,其它日志文件都是文本文件。

使用日志有优点也有缺点。启动日志后,虽然可以对 MySQL 服务器性能进行维护,但是会降低 MySQL 的执行速度。例如,一个查询操作比较频繁的 MySQL 中,记录通用查询日志和慢查询日志要花费很多的时间。日志文件还会占用大量的硬盘空间。对于用户量非常大、操作非常频繁的数据库,日志文件需要的存储空间甚至比数据库文件需要的存储空间还要大。因此,是否启动日志,启动什么类型的日志要根据具体的应用来决定。

这里主要讲解【慢查询日志】,通俗的说,MySQL 慢查询日志是排查问题的 SQL 语句,以及检查当前 MySQL 性能的一个重要功能。如果不是调优需要,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。不过相对于排查问题来说,这点性能问题不足挂齿。

慢查询命令:

# 慢查询命令
SHOW VARIABLES LIKE 'slow_query%';

# 查询超过多少秒才记录
SHOW VARIABLES LIKE 'long_query_time';

 

慢查询的日志在我们安装 MySQL 时指定的 data 目录:

 

启动/停止慢查询、设置指定时间

# 启动/停止 慢查询
SET GLOBAL slow_query_log=ON/OFF;

然后修改 my.ini 的慢查询时间配置,如图,搜索【long_query_time】:修改时间为 0.01 秒,为了测试使用。

 

网上说的【set global long_query_time=1】 不靠谱,重启 MySQL 服务后就失效了,达不到我们的要求,还是老实点修改 my.ini 配置文件吧。

设置好之后重启 MySQL 服务器就生效了。

OK,我们定位了慢查询之后,就针对慢查询做一系列的调优了。

 

我们先在数据库里新增1万条测试数据,可以参考博客:https://blog.csdn.net/BiandanLoveyou/article/details/116280263

 

MySQL 性能优化讲解

定位效率低的数据库语句,并做分析和优化。

比如我们设置了慢查询的时间上限是 0.01 秒,超过0.01秒的数据库语句会被记录到慢查询日志:

select * from t_user
where user_name like '%名%'
group by user_name
order by user_name;

然后打开慢查询日志可以看到类似如下信息,包括执行时间、执行的SQL:

# Time: 2021-04-30T05:08:13.779360Z
# User@Host: root[root] @ localhost [127.0.0.1]  Id:     6
# Query_time: 0.020624  Lock_time: 0.000085 Rows_sent: 10000  Rows_examined: 30044
SET timestamp=1619759293;
select * from t_user
where user_name like '%名%'
group by user_name
order by user_name;

OK,定位出慢查询后,我们就是要优化慢查询了。

分析:使用 explain 关键字分析慢查询语句

我们在 select 关键字前,加上【explain】关键字,来分析慢查询。通过 explain 关键字知道查询效率低下的原因,从而改进我们的查询,让查询优化器能更好的工作。:

explain select * from t_user
where user_name like '%名%'
group by user_name
order by user_name;

执行结果:

各项说明:

id 代表执行编号,select_type 代表本行是简单还是复杂查询,table 代表的是访问的哪张表,
type 代表的是访问类型,这里的all是最坏的一种情况,代表全表扫描,

possible_keys 表示哪一些索引有利于高效的查找,key代表mysql决定采用哪个索引来优化查询,key_len代表显示mysql在索引里使用的字节数,

ref代表之前的表在key列记录的索引中查找值所用的列或常量,rows代表为了找到所需的行而需要读取的行数,估算值,不精确,filtered代表按表条件筛选的行的百分比,Extra代表额外信息

type 的其它类型:

 

重点关注 Extra 这一项,如果 Extra 出现以下2项内容说明没有用到索引: Using temporary; Using filesort

Using temporary:表示MySQL在对查询结果排序时使用临时表。常见于 order by 和 group by。【将排序的结果存储到一张临时表中,方便后面做各种查询使用】

Using filesort:表示 MySQL 会对结果使用一个外部索引排序,而不是从表里按索引次序读到相关内容。 可能在内存或磁盘上进行排序。MySQL无法利用索引完成的排序操作称为“文件排序”。

优化:经常查询的字段增加索引

但是,我们怎么知道哪些字段创建索引合适呢?索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引。

# 给 user_name 字段创建索引
alter table t_user add index userNameIndex(user_name);

执行结果:

再次执行查询的分析语句:

说明:

①经常查询的字段要设置索引,使用索引比不使用索引的查询效率更高。

②like 关键字模糊查询时,如果匹配字符串的第一个字符为 % 时索引不会被使用。如果 % 不在第一个位置,索引就会被使用。因此上面的写法还可以优化。

③where条件有 or 关键字时,or 的每一项都要有索引时,才会使用索引,否则不会使用索引。

④经过普通运算或函数运算后的索引字段不会使用索引。比如:select * from users where YEAR(adddate)<2021; 这句 SQL 就不会使用索引。可以改为:select * from users where adddate<‘2021-01-01';

⑤使用连接查询代替子查询。因为在子查询时,MySQL 需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句在临时表中查询记录。查询完毕后,MySQL需要撤销这些临时表。因此,子查询的速度会受到一定的影响。如果查询的数据量比较大,这种影响就会随之增大。而连接查询不需要建立临时表,其速度比子查询要快。

⑥如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引。

⑦联合索引的最左前缀匹配原则。如果在一张表中,存在联合索引的话,在根据条件查询的时候必须要加上第一个索引条件。比如创建两个列的联合索引(id、user_name),在where条件中,第一个条件需要使用有索引的列,一直到没有索引的列为止。可以参考此博客:https://blog.csdn.net/u013568373/article/details/93891531

⑧使用分表分库提高数据库查询效率。中间件会将此语句根据有n个子表,拆分成n条语句:如select * from user1,select * from user2,select * from user3等多条sql语句,去子表中查询。然后将结果返回给中间件,中间件进行汇总返回给客户端。而这些子语句是同时执行的,所以查询效率非常高。

⑨not in 和 <> 操作都不会使用索引,将进行全表扫描。not in 可以 not exists 代替,【id<>5】则可使用【 id>5 or id<5 】来代替。

⑩in 和 not in 也要慎用。对于连续的数值,能用 between 就不要用 in :select id from t_user where num between 1 and 5;

11、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

12、在硬件配置上,加大物理内存,提高文件系统性能。SSD硬盘代替SAS硬盘。或者做数据库集群。

 

 

标签:name,MySQL,查询,索引,user,调优篇,系列学习,日志
来源: https://blog.csdn.net/BiandanLoveyou/article/details/116245391