当前位置: 首页 > news >正文

【MySQL】慢查寻的发现和解决优化(思维导图版)

“慢查询”是数据库领域的核心性能问题之一,指执行时间超过预设阈值(如 MySQL 的 long_query_time,默认 10 秒)的 SQL 语句。解决慢查询需遵循“定位问题 → 分析根源 → 优化执行 → 验证效果”的闭环流程,具体方案可从 查询本身、索引、数据库配置、架构设计 四个维度展开。

EXPLAIN

通过日志工具定位到慢查询后,需用 EXPLAIN 命令分析其 执行计划,明确慢的原因。EXPLAIN 会展示查询的索引使用、表连接方式、数据扫描量等关键信息。

①、id 列:查询的标识符。

- id 越大越先执行;相同 id 按从上到下顺序执行

复杂子查询可考虑改为 JOIN,减少嵌套层级

②、select_type 列:查询的类型。常见的类型有:

  • SIMPLE:简单查询,不包含子查询或者 UNION 查询。
  • PRIMARY:查询中如果包含子查询,则最外层查询被标记为 PRIMARY。
  • SUBQUERY:子查询。
  • DERIVED:派生表的 SELECT,FROM 子句的子查询。

- 出现 DERIVED(衍生表)可能产生临时表;
- 多层 SUBQUERY 可能影响性能

避免过度使用子查询,优先用 JOIN 替代

③、table 列:查的哪个表。

④、type 列:访问类型(查询效率等级)表示 MySQL 在表中找到所需行的方式,性能从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL。

  • system,表只有一行,一般是系统表,往往不需要进行磁盘 IO,速度非常快
  • const:表中只有一行匹配,或通过主键或唯一索引获取单行记录。性能非常高。
  • eq_ref:对于每个来自上一张表的记录,最多只返回一条匹配记录,通常用于多表关联且使用主键或唯一索引的查询。效率非常高,适合多表关联查询。
  • ref:使用非唯一索引或前缀索引查询的情况,返回符合条件的多行记录。通常用于普通索引或联合索引查询,效率较高,但不如 const 和 eq_ref。
  • range:只检索给定范围的行,使用索引来检索。在where语句中使用 bettween...and<><=in 等条件查询 type 都是 range
  • index:全索引扫描,即扫描整个索引而不访问数据行。
  • ALL:全表扫描,效率最低。

异常ALL(全表扫描)、index(全索引扫描);
理想constrefrange

确保 WHERE/JOIN 字段有索引,避免无过滤条件的查询

⑤、possible_keys 列:可能会用到的索引,但并不一定实际被使用。

⑥、key 列:实际使用的索引。NULL 表示未使用索引(即使 possible_keys 有值)检查索引是否被正确使用(如避免函数操作索引字段)

⑦、key_len 列:MySQL 决定使用的索引长度(以字节为单位)。判断查询使用了联合索引的哪些字段。联合索引 idx_columns(column1, column2),如果 key_len 等于 column1 的长度,表示查询只使用了 column1。调整联合索引顺序,确保过滤性强的字段在前

⑧、ref 列:用于与索引列比较的值来源。

  • const:表示常量,这个值是在查询中被固定的。例如在 WHERE column = 'value'中。
  • 一个或多个列的名称,通常在 JOIN 操作中,表示 JOIN 条件依赖的字段。
  • NULL,表示没有使用索引,或者查询使用的是全表扫描。

⑨、rows 列:估算查到结果集需要扫描的数据行数,原则上 rows 越少越好。数值远大于实际返回的行数,说明过滤条件差。优化 WHERE 条件,增加过滤性强的条件(如用精确匹配替代模糊匹配)。

⑩、Extra 列:附加信息。

  • Using index:表示用了覆盖索引。
  • Using where:表示使用了 WHERE 过滤。
  • Using temporary :表示使用了临时表来存储中间结果。

异常Using filesort(文件排序)、Using temporary(临时表);
理想Using index(覆盖索引)

- 对 Using filesort:为排序字段建索引;
- 对 Using temporary:避免非索引字段 GROUP BY
- 优先实现 Using index(查询字段全在索引中)

示例:一条慢查询的 EXPLAIN 结果若显示 type: ALLkey: NULLrows: 100000,说明是“未走索引的全表扫描”,根源明确。

解决方案:从 4 个维度优化

维度 1:优化查询语句本身(最直接,成本最低)

多数慢查询是因 SQL 写法不规范导致:

  1. 避免全表扫描/全索引扫描

禁止无过滤条件的 SELECT *(如 SELECT * FROM user)。

  1. 优化分页查询

对于 LIMIT offset, size深度分页问题,不要直接 LIMIT 1000000, 20

延迟关联(Late Row Lookups)和书签(Seek Method)是两种优化分页查询的有效方法。

①、延迟关联

延迟关联适用于需要从多个表中获取数据且主表行数较多的情况。它首先从索引表中检索出需要的行 ID,然后再根据这些 ID 去关联其他的表获取详细信息。

避免了每条id都要回表(查聚簇索引)

SELECT e.id, e.name, d.details
FROM (SELECT idFROM employeesORDER BY idLIMIT 1000, 20
) AS sub
JOIN employees e ON sub.id = e.id
JOIN department d ON e.department_id = d.id;

②、书签(Seek Method)

书签方法通过记住上一次查询返回的最后一行的某个值,然后下一次查询从这个值开始,避免了扫描大量不需要的行。

SELECT id, name
FROM users
WHERE id > last_max_id  -- 假设last_max_id是上一页最后一行的ID
ORDER BY id
LIMIT 20;
  1. join 优化

①、禁止无限制的 IN 子句(如 IN (1,2,...,10000)),改用 JOIN 或分批查询。

低效:SELECT * FROM order WHERE user_id IN (SELECT id FROM user WHERE status=1);
优化:SELECT o.* FROM order o JOIN user u ON o.user_id = u.id WHERE u.status=1;

若 IN 中的值是离散的 “硬编码列表”(如 IN (1,2,...,10000)),则将 10000 个值拆分为多个小批次(如每批 500 个),执行多次 IN (1-500)IN (501-1000)...,避免单次 SQL 过长和匹配压力。

②、小表驱动大表

在执行 JOIN 操作时,应尽量让行数较少的表(小表)驱动行数较多的表(大表),这样建立连接的次数就少,查询速度就快了。

③、适当增加冗余字段

在某些情况下,通过在表中适当增加冗余字段来避免 JOIN 操作,可以提高查询效率,尤其是在高频查询的场景下。

④ 避免 CROSS JOIN(笛卡尔积),必须加连接条件。

  1. UNION 优化

条件下推:将 where、limit 等子句下推到 union 的各个子查询中,以便优化器可以充分利用这些条件进行优化。

SELECT * FROM (SELECT * FROM AUNIONSELECT * FROM B
) AS sub
WHERE sub.id = 1;

可以改写成:

SELECT * FROM A WHERE id = 1
UNION
SELECT * FROM B WHERE id = 1;

通过将查询条件下推到 UNION 的每个分支中,每个分支查询都只处理满足条件的数据,减少了不必要的数据合并和过滤。

维度 2:优化索引(提升查询效率的核心)
  1. 有效使用
    • WHERE子句、ORDER BYGROUP BY以及 JOIN ... ON的字段考虑创建索引。避免 ORDER BY/GROUP BY 对非索引字段操作,会触发 Using filesort(内存/磁盘排序)
    • 多条件用联合索引(最左前缀原则)
    • 利用覆盖索引: 让SQL要查询的字段完全包含在索引中,避免回表
    • 启用索引下推,减少回表次数。
    • 使用前缀索引,减少体积
    • 范围查询(>, <, BETWEEN)的字段放在末尾,避免导致后续索引字段失效
  1. 避免索引失效:
    • 字段操作:避免在 WHERE 子句中对字段做“函数/运算操作”
    • 操作符:避免使用 != 或者 <> 操作符,尽可能使用 =><BETWEEN
    • 数据类型:隐式类型转换(如字符串不加引号)
    • 连接方式:避免 WHERE 子句用 OR 连接非索引字段,改用 UNION
    • 避免LIKE 以通配符开头(%xxx / %xxx%)
  1. 优化无效/低效索引
    • 删除“未被使用的索引”(可通过 sys.schema_unused_indexes 或慢查询日志排查)。
    • 合并“重复索引”(若 idx_a_b 已存在,idx_a 可能冗余)。
    • 对“区分度低的字段”(如 gender 只有 0/1)不建索引。
维度 3:数据库设计优化

也可以优化数据库配置,加大内存缓存,调整连接池参数等等,这个不了解。

  • 数据类型: 使用适当的数据类型(如用INT存数字,而不是VARCHAR)。
  • 范式与反范式: 在数据一致性和查询性能之间做权衡。有时可以适当做反范式设计,增加一些冗余字段来避免复杂的JOIN
维度 4:架构层面优化(解决根本性、高并发问题)

当单库单表性能达到瓶颈(如数据量超 1000 万行,并发 QPS 超 1 万),需从架构层面拆分压力:

  1. 读写分离

主库负责“写操作”,从库负责“读操作”,通过主从复制同步数据。

  1. 分库分表

当单表数据量过大(如超 5000 万行),索引和查询效率会下降,需拆分表:

  1. 引入缓存

将高频访问的“热点数据”缓存到内存中,适合“读多写少”的数据。

  1. 使用列存数据库/搜索引擎
  • 对“海量数据分析场景”(如日志分析、报表统计),传统行存数据库(MySQL/PostgreSQL)效率低,可改用列存数据库(如 ClickHouse)。
  • 对“全文检索场景”(如商品搜索、文章检索),用搜索引擎(如 Elasticsearch)替代数据库的 LIKE 查询,支持分词、高亮、排序等高级功能。
http://www.dtcms.com/a/511887.html

相关文章:

  • gbase8s之.net8连接8s之mysql模式(windows)demo
  • 【AI】大模型之深度估计
  • 7.1 EXTI工作原理
  • LazyLLM教程 | 第11讲:性能优化指南:从冷启动到响应加速你的RAG
  • windows后渗透中常用的信息收集命令
  • 初始化node项目express,项目结构介绍
  • Optuna - 自动调参利器python实例
  • 新网站做优化要准备什么合肥网站建设哪个公司做得比较好
  • 提供服务好的网站制作网站怎么做会员系统
  • 绍兴网站建设推广宁夏建设管理局网站
  • 【面向小白】git rebase全面总结,什么时候用rebase
  • Kubernates的部署(从安装到实践)
  • C++ 11
  • (一)Flutter 插件项目demo预览图
  • 两学一做 答题 网站好看到让人久久不忘的电影
  • iOS混淆实战:多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|Ipa Guard 实战)
  • 完整网站开发视频教程wordpress网页图片加载很慢
  • 软考高级-系统架构设计师历年案例专题一:软件架构设计
  • SQL入门:分页查询-原理、优化与实战
  • Linux OS文件系统资源消耗分析:系统架构与优化实践
  • 系统架构之高可用
  • C 语言编译与链接入门
  • 驾校管理系统|基于java和小程序的驾校管理系统设计与实现(源码+数据库+文档)
  • [Java数据结构与算法] 详解Map和Set接口
  • 疲劳驾驶检测提升驾驶安全 疲劳行为检测 驾驶员疲劳检测系统 疲劳检测系统价格
  • 文件上传漏洞和绕过技术
  • 网站开发协议模板单页网站怎么优化
  • MEMS电容式加速度计虚拟仿真实验
  • 第一个 Python 程序
  • AI学习-数据图片批量改名-win环境下-使用python脚本