慢SQL减少回表手段

Mysql数据查询无疑就是IO过程,慢SQL的优化本质上其实就是一种减少IO的优化过程,首先了解一下Mysql架构:

  • 客户端连接器: 客户端连接数据库服务的驱动,支持多种开发语言
  • 连接池: 负责存储和管理客户端与数据库的连接,一个线程负责管理一个连接
  • 系统管理和控制工具: 提供备份恢复,安全管理等功能
  • SQL接口: 接收客户端发送的各种SQL请求,并返回结果
  • 解析器: 对SQL语句进行词法解析,语法解析和对象权限检查,并生成语法树
  • 查询优化器: 对查询进行改写,通过对不同执行路径的cost对比,生成最优的执行计划。
  • 缓存: 查询缓存,主要缓存查询的结果,为重复的查询节省执行的时间(默认关闭,8.0废弃)
  • 存储引擎: 存储引擎负责MySQL中数据的存储与提取,与底层系统文件进行交互。MySQL存储引擎是插件式的,服务器中的查询执行引擎通过接口与存储引擎进行通信,接口屏蔽了不同存储引擎之间的差异 。
  • 系统文件: 存储数据和日志的物理文件

Mysql查询链路

索引优化本质上就是对执行计划干预,通过建立和调整合适的索引策略,来使得执行器能更优、更高效的执行SQL。

Explain返回语句中使用的每个表的一行信息 。它按照 MySQL 在处理语句时读取表的顺序列出了输出中的表。MySQL 使用嵌套循环连接方法来解析所有连接。这意味着MySQL从第一个表中读取一行,然后在第二个表、第三个表等中找到匹配的行。当所有表都处理完毕后,MySQL 输出选定的列并回溯表列表,直到找到有更多匹配行的表。从此表中读取下一行,并继续处理下一个表。

可以看得出来此过程需要频繁回表操作,如果不能借助有效的优化手段,就可能导致严重的效能问题。【Mysql】 InnoDB引擎深入- 二级索引、联合索引、回表、索引覆盖_二级索引叶子节点-优快云博客

一般减少回表消耗的本质就是减少IO开销,一般常用手段为:

1、索引覆盖

2、索引下推

索引覆盖

我们知道对于二级索引来说,索引结构中只会存储索引列信息+主键ID,如果需要额外的资讯信息,需要通过主键ID到聚簇索引结构中检索,这样的过程叫做回表,那索引覆盖的本质就是期望可以一次性通过二级索引拿到需要栏位资讯,较少回表操作。

做法很简单,建立二级索引,索引栏位覆盖所需要查询的栏位即可。

例如:

当前索引mkp_wo_info_b001(tenantsid)

添加plan_no到索引中

mkp_wo_info_b001(tenantsid,plan_no)

 需要注意的是索引覆盖是为了减少回表次数,而二级索引是用于提高检索效率,需要遵循最左原则,如果在已存在的二级索引上进行索引覆盖操作,注意不要影响二级索引的正常使用,建议覆盖栏位滞后。

索引下推(ICP)

索引条件下推(ICP)是针对 MySQL 使用索引从表中检索行的情况的优化。如果没有 ICP,存储引擎将遍历索引来定位基表中的行,并将它们返回到 MySQL 服务器,由 MySQL 服务器评估这些WHERE行的条件。启用 ICP 后,如果 WHERE可以仅使用索引中的列来评估部分条件,则 MySQL 服务器会将这部分条件推WHERE送到存储引擎。然后,存储引擎通过使用索引条目来评估推送的索引条件,并且仅当满足该条件时才从表中读取行。ICP可以减少存储引擎必须访问基表的次数以及MySQL服务器必须访问存储引擎的次数。

说白了索引下推的目的就是将where条件的过滤从Mysql服务层下推到存储引擎进行处理,较少返回的数据量,也就意味着减少后续需要回表的次数。

需要注意的是对于InnoDB表来说,ICP仅用于二级索引。ICP的目标是减少全行读取的次数,从而减少I/O操作。对于 InnoDB聚集索引,完整的记录已经读入缓冲区InnoDB 。在这种情况下使用 ICP 不会减少 I/O

举例:

现在有索引mkp_wo_info_b001 (`tenantsid`, `wo_no`, `eoc_company_id`)

tenantsid bigint(20)、wo_no varchar(50)、eoc_company_id varchar(50)

测试:

key_len计算:8(bigint)+50*3(utf-8)+1(len)+1(null)+50*3+1+1 = 312

可以看出来上面使用到的条件:tenantsid=297471165657664 and wo_no = 'Y512-202110260001' and eoc_company_id = '1' 是完全使用到了索引,这也是理论之内的。

如果我们去掉wo_no条件,变成tenantsid=297471165657664  and eoc_company_id = '1' , 根据最左原则要求,这里只能使用到tenantsid,索引长度为8:

 但是我们发现在Extra中发现了 Using index condition,这个就代表了使用到了索引下推。

解释一下:

不使用索引条件下推时索引扫描如何进行:

1、通过tenantsid读取下一行,然后通过查询到的索引数据进行回表获取资讯

2、WHERE测试适用于此表的条件 部分,也就是在Server层进行eoc_company_id条件的过滤

使用索引条件下推时索引扫描如何进行:

1、通过tenantsid读取下一行

2、检查过where适用于该表的条件 部分,并且可以仅使用索引列进行检查。如果不满足条件,则继续查找下一行的索引元组。也就是说在索引查询时(存储引擎检索时)就已经将where条件中eoc_company_id条件下沉进行过滤操作,此时获取到的数据范围会更小。

3、如果满足条件,则使用索引元组定位并读取全表行

WHERE 测试适用于此表的条件 的其余部分。根据测试结果接受或拒绝该行。

当使用索引条件下推时,输出显示 Using index condition在 列中。

### SQL JOIN 操作的优化方法 为了提高多 JOIN 查询的速度,可以从以下几个方面入手: #### 1. 使用合适的索引 对于涉及多个连接的操作,确保参与连接条件的列上有适当的索引非常重要。特别是当这些列频繁用于 `WHERE` 子句中的过滤条件或是作为外键关系的一部分时。 例如,在订单中如果经常按照日期范围筛选数据,则应该考虑为 `order_date` 字段创建索引[^2]: ```sql CREATE INDEX idx_order_date ON orders(order_date); ``` 同样地,对于其他可能出现在 `ORDER BY`, `GROUP BY`, 或者聚合函数后的字段也应如此处理[^3]。 #### 2. 减少不必要的列读取 只选择真正需要返给应用层的数据项而不是使用通配符(*)来获取全部记录。这不仅减少了网络传输量还降低了服务器端CPU开销。 #### 3. 合理设计JOIN顺序 数据库引擎会尝试自动决定最佳执行计划但是有时手动调整可以带来更好的效果。通常来说左深树结构(即最左边的第一个尽可能小而后续每一步都基于前一次的结果集进行扩展)往往现较好。 #### 4. 避免笛卡尔积现象 确保所有的 join 条件都是有效的并且能够唯一匹配到目标行;否则将会导致两之间形成完全交叉乘积从而极大地增加了计算复杂度。 #### 5. 应用 Profiler 工具分析性能瓶颈 通过使用像 MySQL查询日志或者是 Oracle 提供的各种诊断工具如 AWR 报告等手段收集运行期间的各项指标参数并加以分析定位具体哪一部分消耗过多资源进而采取针对性措施改善效率问题[^1]. ```sql EXPLAIN ANALYZE SELECT o.order_id, c.customer_name FROM orders AS o INNER JOIN customers AS c ON o.customer_id = c.customer_id; ``` 上述命令可以帮助理解当前SQL的实际执行路径及其成本估算情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Survivor001

你可以相信我,如果你愿意的话

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值