高手都是如何做 Mysql 慢 SQL 优化

举报
激流丶 发表于 2023/06/12 07:31:31 2023/06/12
【摘要】 高手都是如何做 Mysql 慢 SQL 优化

tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。

💕💕 推荐:体系化学习Java(Java面试专题)

1、如何定位慢 SQL 问题

定位慢SQL问题可以通过以下几种方法:

1.1、启用MySQL慢查询日志

在MySQL配置文件中开启慢查询日志功能,可以记录执行时间超过一定阈值的SQL语句。

# 开启MySQL慢查询日志可以通过以下步骤实现:

# 1. 编辑MySQL配置文件my.cnf(或my.ini),添加以下配置项:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2
# 其中, `slow_query_log` 表示是否开启慢查询日志, `slow_query_log_file` 表示慢查询日志保存的文件路径, `long_query_time` 表示执行时间超过多少秒的SQL语句会被记录到慢查询日志中。

# 2. 重启MySQL服务,使配置生效。

# 3. 查看慢查询日志,可以使用以下命令:
sudo tail -f /var/log/mysql/mysql-slow.log
# 该命令可以实时查看MySQL慢查询日志,可以按Ctrl+C退出。

# 4. 在慢查询日志中查找慢SQL语句,可以根据执行时间和执行次数等信息进行排序和过滤,找出执行时间较长的SQL语句,进一步分析和优化。

# 注意:开启慢查询日志会对MySQL性能产生一定的影响,因此建议在调试和优化阶段开启,调试结束后关闭。

1.2、分析慢查询日志

使用MySQL提供的工具或第三方工具,对慢查询日志进行分析,可以查看执行时间较长的SQL语句以及执行时间、执行次数等相关信息。
 
分析MySQL慢查询日志的工具有很多,以下是一些常用的工具:

  1. mysqldumpslow:这是MySQL自带的一个工具,可以用来解析慢查询日志文件,并按照执行时间、执行次数等排序,方便查找慢SQL语句。

  2. pt-query-digest:这是Percona Toolkit中的一个工具,可以对慢查询日志进行分析,并生成报告,包括执行时间、执行次数、索引使用情况等信息,帮助定位慢SQL问题。可以使用以下命令安装:
    sudo apt-get install percona-toolkit

  3. MySQL Enterprise Monitor:这是MySQL官方提供的一款性能监控工具,可以实时监控MySQL的性能指标,包括慢查询、锁等问题,帮助发现和解决MySQL性能问题。

  4. VividCortex:这是一款云端的MySQL性能监控工具,可以实时监控MySQL的性能指标,包括慢查询、锁等问题,提供可视化的报告和分析功能,帮助定位和解决MySQL性能问题。

具体哪种工具主要取决于具体需求和使用场景,可以根据实际情况选择合适的工具。

1.3、使用EXPLAIN分析查询计划

使用EXPLAIN语句可以查看MySQL执行SQL语句的查询计划,包括使用了哪些索引、表的连接方式等信息。可以通过分析查询计划,找出影响查询性能的因素。

EXPLAIN是MySQL的一个关键字,用于分析查询语句的执行计划,可以帮助我们优化查询性能。使用EXPLAIN需要在查询语句前加上EXPLAIN关键字,例如:

EXPLAIN SELECT * FROM table WHERE id = 1;

执行以上语句后,MySQL会返回一个执行计划,包括查询使用的索引、查询类型、扫描行数等信息,例如:

| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | table | const | PRIMARY       | PRIMARY | 4       | const |    1 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+

其中,各列的含义如下:

  • id:查询的标识符,每个查询都有一个唯一的标识符。
  • select_type:查询的类型,包括SIMPLE(简单查询)、PRIMARY(主键查询)、UNION(联合查询)等。
  • table:查询的表名。
  • type:查询的类型,包括const(常量查询)、eq_ref(唯一索引查询)、ref(非唯一索引查询)、range(范围查询)等。
  • possible_keys:查询可能使用的索引。
  • key:查询实际使用的索引。
  • key_len:索引使用的长度。
  • ref:索引使用的列。
  • rows:扫描的行数。
  • Extra:额外的信息,例如Using index表示使用了索引优化查询。 
     
    通过分析EXPLAIN的结果,可以判断查询语句的性能瓶颈所在,例如是否使用了索引、是否存在全表扫描等问题,进而优化查询语句,提高查询性能。

1.4、使用性能分析工具

MySQL提供了一些性能分析工具,例如 MySQL Performance Schema 和 MySQL Enterprise Monitor 等,可以实时监控MySQL的性能指标,帮助定位慢SQL问题。

MySQL Performance Schema 是 MySQL 5.5.3 及以上版本中的一个特性,用于收集 MySQL 实例的性能数据,包括 SQL 语句执行时间、锁等待时间、IO 操作等等。启用 Performance Schema 可以帮助我们更好地了解 MySQL 实例的性能瓶颈,从而进行优化。而 MySQL Enterprise Monitor 是 MySQL 提供的一个监控和管理工具,需要下载安装的,这里我就不做介绍了,感兴趣的同学可以去下载安装下,我这里重点介绍下 MySQL Performance Schema。
 
以下是在 MySQL 5.7 中启用 Performance Schema 的步骤:

  1. 修改 my.cnf 配置文件,添加以下配置项:
[mysqld]
performance_schema=ON
  1. 重启 MySQL 服务,使配置生效。
  2. 连接到 MySQL 实例,使用以下命令检查 Performance Schema 是否启用:c
SHOW VARIABLES LIKE 'performance_schema';

如果返回值为 ON,则表示 Performance Schema 已经启用。 
 
4. 使用以下命令查看 Performance Schema 中的事件:

SELECT * FROM performance_schema.events_statements_summary_by_digest;

以上命令将返回 Performance Schema 中所有 SQL 语句的执行时间、执行次数、平均执行时间等信息。 
 
注意:启用 Performance Schema 后会对 MySQL 实例的性能产生一定的影响,因此在生产环境中需要谨慎使用。可以根据实际情况选择启用或禁用 Performance Schema。

2、如何针对慢 SQL 优化

优化 SQL 语句的方法包括以下几个方面:

1. 添加索引:索引是提高 SQL 查询效率的重要手段。通过添加索引,可以加快查询速度,减少全表扫描的时间。但是,索引也会占用额外的磁盘空间和内存,过多的索引会影响数据库性能。因此,在添加索引时需要根据实际情况进行分析和优化。

2. 修改查询条件:通过修改查询条件,可以减少查询数据的数量,从而提高查询效率。例如,可以添加限制条件、修改排序方式、合并查询语句等。

3. 分解查询语句:如果查询语句比较复杂,可以考虑将查询语句分解为多个简单的查询语句。通过分解查询语句,可以减少查询数据的数量,提高查询效率。

4. 优化子查询:子查询是查询效率较低的一种查询方式。如果查询中包含子查询,可以考虑将子查询转化为连接查询或者其他方式。

5. 避免使用通配符:通配符查询效率较低,应该尽量避免使用通配符查询。如果必须使用通配符查询,可以通过添加索引和限制查询范围等方式来提高查询效率。
 
 6. 使用优化器:MySQL 自带的优化器可以自动优化查询语句,提高查询效率。可以通过设置优化器参数来调整优化器的行为,从而达到优化查询效率的目的。

需要注意的是,在优化 SQL 语句时,应该根据实际情况进行分析和优化,避免过度优化和不必要的优化。同时,优化 SQL 语句需要进行测试和验证,确保优化后的 SQL 语句能够正确地执行,并且性能得到了提升。

其实在生产过程中,我们通过设置一个好的索引就能解决大多数慢 SQL,如果索引也优化不了了,那就只能业务上做拆分了,通过代码去优化,在大数据场景下冗余、物化视图、预查询、缓存等等手段也可以用于解决查询慢的问题。

3、建索引需要遵循什么原则

3.1、建索引需要遵循以下原则:

  1. 索引应该被建立在经常用于查询的列上。通过建立索引可以加快查询速度,但是过多的索引会影响数据库的性能,因此需要根据实际情况进行分析和优化。
  2. 索引应该被建立在唯一性较高的列上。例如,主键列和唯一性约束列都是适合建立索引的列。
  3. 索引应该被建立在数据量较大的表上。对于数据量比较小的表,建立索引的效果并不明显。
  4. 索引应该被建立在经常被用于连接的列上。例如,连接两个表的列应该被建立索引,可以加快连接操作的速度。
  5. 索引应该被建立在经常被用于排序和分组的列上。通过建立索引可以加快排序和分组操作的速度。
  6. 避免建立过多的索引。过多的索引会占用额外的磁盘空间和内存,影响数据库的性能。因此,需要根据实际情况进行分析和优化,避免建立过多的索引。
  7. 避免在大文本和二进制列上建立索引。这些列的数据量比较大,建立索引会占用大量的磁盘空间和内存,影响数据库的性能。

需要注意的是,索引不是建的越多越好,也不是什么字段建索引都能有很好的效果,而且在建立索引时,需要根据实际情况进行分析和优化,避免过度索引和不必要的索引。同时,需要定期对索引进行优化和维护,确保索引的有效性和性能。

3.2 最左前缀原则

要让 SQL 能命中索引,需要遵循最左前缀原则,最左前缀原则需要遵循以下情况:

  1. 查询条件必须包含索引的最左前缀列,才能利用索引进行查询。
  2. 查询条件中可以包含索引的前缀列,但不能包含索引的后缀列。
  3. 查询条件中可以包含索引的非前缀列,但是会导致索引失效,无法利用索引进行查询。

下面举例说明:
假设有一个表student,包含以下列:id, name, age, gender,其中id列为主键列,同时创建了一个联合索引idx_name_age_gender(name, age, gender)。
 1. 查询条件包含索引的最左前缀列
 例如,查询name为’张三’的学生信息,可以使用如下SQL语句:

 SELECT * FROM student WHERE name = '张三';

该查询条件包含了索引的最左前缀列name,可以利用索引进行查询。
 
 2. 查询条件包含索引的前缀列,但不能包含索引的后缀列
 例如,查询name为’张三’且age为18岁的学生信息,可以使用如下SQL语句:

SELECT * FROM student WHERE name = '张三' AND age = 18;

该查询条件包含了索引的前缀列name和age,可以利用索引进行查询。
 但是,如果查询条件中只包含age列,不能利用索引进行查询,需要进行全表扫描。例如:

SELECT * FROM student WHERE age = 18;

3. 查询条件中包含索引的非前缀列,导致索引失效
 例如,查询gender为’男’的学生信息,可以使用如下SQL语句:

 SELECT * FROM student WHERE gender = '男';

该查询条件包含了索引的非前缀列gender,会导致索引失效,需要进行全表扫描。

3.3、哪些情况会破坏最左前缀原则

以下情况会破坏最左前缀原则:

  1. 查询条件中包含了索引列的后缀列,而不是前缀列。这种情况下,索引无法被利用,需要进行全表扫描。
  2. 查询条件中包含了索引列的非前缀列。这种情况下,索引会失效,需要进行全表扫描。
  3. 查询条件中使用了函数或表达式,导致无法利用索引。例如:
SELECT * FROM table WHERE YEAR(date_column) = 2021; 

这种情况下,YEAR(date_column)是一个表达式,无法利用索引。

  1. 查询条件中使用了通配符(如%),导致无法利用索引。例如:
SELECT * FROM table WHERE name LIKE '张%'; 

这种情况下,LIKE '张%'中的通配符%会导致无法利用索引。

  1. 查询条件中使用了OR操作符,导致无法利用索引。例如:
SELECT * FROM table WHERE col1 = 'value1' OR col2 = 'value2'; 

这种情况下,OR操作符会导致无法利用索引。

总之,破坏最左前缀原则的情况主要是查询条件与索引的匹配度不高,导致无法利用索引进行查询。因此,在设计索引和查询时,需要注意遵循最左前缀原则,选择合适的索引列和查询条件,以充分利用索引提高查询效率。

4、Mysql 索引的原理

4.1、索引介绍和原理

MySQL索引是一种数据结构,用于提高查询效率。它通过将索引列的值与行的物理位置关联起来,可以快速地定位满足查询条件的行。MySQL支持多种类型的索引,包括B-tree索引、哈希索引、全文索引等。

1.B-tree索引是MySQL中最常用的索引类型。它是一种平衡树结构,可以快速地定位满足查询条件的行。B-tree索引的原理是将索引列的值按照一定的顺序存储在B-tree中,每个节点包含多个索引值和对应的物理位置指针,可以通过二分查找快速定位到目标行。B-tree索引不仅可以用于等值查询,还可以用于范围查询和排序等操作。

2.哈希索引是一种基于哈希表的索引类型。它将索引列的值通过哈希函数转换为哈希值,并将哈希值与对应的物理位置关联起来。哈希索引的查询效率非常高,但是它只支持等值查询,不支持范围查询和排序等操作。此外,哈希索引的缺点是哈希冲突较多时,查询效率会降低。

3.全文索引是一种用于全文搜索的索引类型。它可以对文本类型的列进行索引,并支持全文搜索、模糊搜索等操作。全文索引的原理是将文本分词后,将每个词作为索引值存储在倒排索引中,倒排索引记录了每个词在哪些行中出现过。查询时,可以通过倒排索引快速定位到包含目标词的行。

除了以上三种常见的索引类型,MySQL还支持空间索引、前缀索引、多列索引等类型的索引。索引的使用需要根据具体的业务场景和查询需求进行选择和设计,合理的索引可以大大提高查询效率,但是过多或不合理的索引也会降低写入性能和占用存储空间。

4.2、磁盘 IO 与预读

磁盘IO是指计算机从磁盘读取或写入数据的操作。由于磁盘的读写速度比内存慢很多,因此磁盘IO通常是系统性能的瓶颈之一。为了提高磁盘IO的效率,可以使用磁盘预读技术。

磁盘预读是指在读取一个数据块时,顺便将其后续的若干个数据块也读取到内存中,以便于后续的访问。这样可以减少磁盘IO的次数,提高数据访问的效率。磁盘预读一般分为两种方式:顺序预读和随机预读。

顺序预读是指在读取一个数据块时,将其后续的若干个数据块也顺序地读取到内存中。这种方式适用于顺序访问的场景,如扫描整个表或索引。在MySQL中,InnoDB存储引擎会自动进行顺序预读,以提高查询效率。

随机预读是指在读取一个数据块时,将其后续的若干个数据块也读取到内存中,但是读取的顺序是随机的。这种方式适用于随机访问的场景,如使用索引进行查询。在MySQL中,可以通过设置innodb_read_io_threads参数来控制随机预读的线程数。

虽然磁盘预读可以提高磁盘IO的效率,但是也会占用更多的内存资源。因此,在使用磁盘预读时需要根据具体的业务场景和硬件配置进行权衡,以达到最优的性能和资源利用率。

5、详解 B+ 树

5.1、什么是 B+ 树

在这里插入图片描述

B+树是一种常用的数据结构,广泛应用于数据库和文件系统等领域。它是一种多路搜索树,每个节点可以存储多个关键字和对应的数据指针。B+树具有以下特点:
 
 1. 多路搜索:B+树的每个节点可以存储多个关键字和对应的数据指针,因此可以减少树的高度,提高搜索效率。
 2. 平衡性:B+树是一种平衡树,所有叶子节点的深度相同,因此可以保证搜索效率的稳定性。
 3. 顺序访问:B+树的叶子节点组成一个有序链表,可以支持范围查询和排序等操作。
 4. 磁盘友好:B+树的节点大小通常和磁盘块大小相同,因此可以减少磁盘IO次数,提高磁盘访问效率。

B+树的结构和操作可以分为以下几个部分:
 1. 根节点:B+树的根节点是一个特殊的节点,通常包含少量的关键字和指向子节点的指针。
 2. 叶子节点:B+树的叶子节点存储数据指针和关键字,通常按照关键字的大小顺序组成一个有序链表。
 3. 内部节点:B+树的内部节点存储关键字和指向子节点的指针,通常按照关键字的大小顺序组织。
 4. 插入操作:B+树的插入操作通常从根节点开始,沿着关键字的大小顺序找到合适的叶子节点,将新的关键字和数据指针插入到叶子节点中,并根据需要调整树的结构。
 5. 删除操作:B+树的删除操作通常从根节点开始,沿着关键字的大小顺序找到合适的叶子节点,删除指定的关键字和数据指针,并根据需要调整树的结构。
 6. 查找操作:B+树的查找操作通常从根节点开始,沿着关键字的大小顺序找到合适的叶子节点,根据关键字查找对应的数据指针。
 B+树是一种高效的数据结构,可以支持快速的插入、删除和查找操作,尤其适用于需要频繁访问磁盘的场景。在数据库和文件系统等领域,B+树已经成为一种常用的数据结构,广泛应用于各种系统中。

5.2、b+树的查找过程

B+树的查找过程通常从根节点开始,根据关键字的大小顺序沿着树的分支向下查找,直到找到包含目标关键字的叶子节点。具体步骤如下:

  1. 从根节点开始,比较目标关键字和当前节点中的关键字,根据大小关系选择相应的子节点。
  2. 如果当前节点是叶子节点,则在叶子节点中查找目标关键字,如果找到则返回对应的数据指针;否则表示目标关键字不存在于树中,返回空值。
  3. 如果当前节点是内部节点,则重复步骤1和步骤2,直到找到包含目标关键字的叶子节点。

在B+树中,所有叶子节点按照关键字的大小顺序组成一个有序链表,因此可以支持范围查询和排序等操作。如果需要查找一个范围内的数据,则可以在有序链表中顺序遍历,直到找到范围内的所有数据为止。

5.3、b+树性质

B+树是一种常用的索引结构,具有以下性质:

  1. 根节点至少有两个子节点。
  2. 每个非叶子节点有k个子节点,其中ceil(m/2) <= k <= m,m为B+树的阶数。
  3. 每个节点中包含k-1个关键字,且关键字按照升序排列。
  4. 所有叶子节点都在同一层,且包含所有关键字的信息和指向对应数据的指针。
  5. 非叶子节点的关键字仅用于索引,不保存数据记录的信息。
  6. 所有节点的子树指针或者指向叶子节点的指针都存储在同一层中,即每个节点的子节点数相同。
  7. 叶子节点之间通过指针相连,形成一个有序链表,可以支持范围查询和排序等操作。

B+树的这些性质保证了B+树的高效性和可靠性,使其成为一种非常适合数据库索引的数据结构。
image.png

💕💕 本文由激流原创
💕💕喜欢的话记得点赞收藏啊

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。