SQL执行计划分析-分页查询

一、SQL 执行计划分析

以下是当前 SQL 的执行计划分析:

plaintext 复制代码
+----+-------------+-------------------------------+------------+------+-------------------------------------------------------------+-------------------------------+---------+-------------+---------+----------+-------------+
| id | select_type | table                         | partitions | type | possible_keys                                               | key                           | key_len | ref         | rows    | filtered | Extra       |
+----+-------------+-------------------------------+------------+------+-------------------------------------------------------------+-------------------------------+---------+-------------+---------+----------+-------------+
|  1 | SIMPLE      | ecif_point_subjects_info_2023 | p202312    | ref  | ecif_point_subjects_info_idx2,ecif_point_subjects_info_idx3 | ecif_point_subjects_info_idx2 | 212     | const,const | 1378916 |   100.00 | Using index |
+----+-------------+-------------------------------+------------+------+-------------------------------------------------------------+-------------------------------+---------+-------------+---------+----------+-------------+
plaintext 复制代码
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                                                                                                                                                                                                           |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Limit/Offset: 5/300 row(s)  (cost=342931.18 rows=5)
    -> Group aggregate: count(1), sum(ecif_point_subjects_info_2023.debt_total_amt), sum(ecif_point_subjects_info_2023.crdt_total_amt)  (cost=342931.18 rows=1378916)
        -> Covering index lookup on ecif_point_subjects_info_2023 using ecif_point_subjects_info_idx2 (batch_date='2023-12-30', batch_id='20231230803')  (cost=205039.58 rows=1378916)
 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

二、执行计划字段详解

1. 基础执行计划字段

  • id :查询的唯一标识符。1 表示这是第一个查询(没有子查询或联合查询)。
  • select_type :查询类型。SIMPLE 表示这是一个简单的查询,不包含子查询或联合查询。
  • table :查询涉及的表名。ecif_point_subjects_info_2023
  • partitions :查询涉及的分区。p202312 表示查询只涉及 2023-12 的数据分区。
  • type :连接类型。ref 表示 MySQL 使用了非唯一索引进行查找。
  • possible_keys :MySQL 可能使用的索引。这里有 ecif_point_subjects_info_idx2ecif_point_subjects_info_idx3
  • key :MySQL 实际使用的索引。ecif_point_subjects_info_idx2 是实际使用的索引。
  • key_len :使用的索引长度。212 字节,这表明索引包含了多个字段(batch_date, batch_id, br_no, tx_br_no, debt_total_amt, crdt_total_amt)。
  • ref :显示索引的哪一列被使用。const,const 表示 batch_datebatch_id 被用作常量值进行查询。
  • rows :MySQL 估计需要扫描的行数。1378916 表示 MySQL 估计需要扫描大约 138 万行数据。
  • filtered :表示查询条件过滤后的行数比例。100.00 表示没有进一步的过滤。
  • Extra :额外的信息。Using index 表示 MySQL 使用了覆盖索引,不需要回表查询。

2. 树状执行计划分析

  • Limit/Offset: 5/300:表示查询结果将被限制为从第 300 行开始,返回 5 行数据。
  • Group aggregate :表示 MySQL 正在执行 GROUP BY 聚合操作,计算 COUNT(1)SUM(debt_total_amt)SUM(crdt_total_amt)
  • Covering index lookup :表示 MySQL 使用了覆盖索引 ecif_point_subjects_info_idx2,直接从索引中获取数据,不需要回表查询。

三、性能分析

1. 索引使用分析

  • 当前查询使用了索引 ecif_point_subjects_info_idx2,该索引包含字段:

    sql 复制代码
    (batch_date, batch_id, br_no, tx_br_no, debt_total_amt, crdt_total_amt)
  • 查询条件 batch_date = '2023-12-30' AND batch_id = '20231230803' 完全匹配索引前缀,因此 MySQL 能够高效地定位数据。

  • GROUP BY br_no, tx_br_no 也匹配索引的前缀字段,因此可以利用索引进行排序,避免额外的排序操作。

2. 扫描行数分析

  • 预计需要扫描 138 万行数据,这主要是因为:
    • GROUP BY 操作需要遍历所有符合条件的数据,进行聚合计算。
    • LIMIT 300, 5 导致 MySQL 需要扫描前 300 行数据,然后丢弃这些数据,只返回最后 5 行。

3. 性能瓶颈

  • 扫描行数大:虽然使用了覆盖索引,但扫描 138 万行数据仍然会带来较大的 I/O 和 CPU 开销。
  • 深分页问题LIMIT 300, 5 是典型的深分页场景,MySQL 需要扫描前 300 行数据并丢弃,效率较低。
  • 聚合操作开销GROUP BY 操作需要对大量数据进行分组和统计,增加了 CPU 消耗。

四、优化建议

1. 优化索引

  • 确保索引字段匹配查询条件和排序字段
    • 当前索引 ecif_point_subjects_info_idx2 已经覆盖了 batch_date, batch_id, br_no, tx_br_no, debt_total_amt, crdt_total_amt,能够支持当前查询。
    • 如果查询中还涉及其他字段(如 dept_no, field2, bal_ind),可以考虑扩展索引字段。

2. 减少扫描行数

  • 缩小查询范围 :如果业务允许,可以进一步缩小查询范围,例如增加 br_notx_br_no 的过滤条件。
  • 使用更细粒度的分区 :如果数据按 br_notx_br_no 分布不均,可以考虑按这些字段进行子分区,以减少扫描的数据量。

3. 优化分页

  • 避免深分页
    • 使用游标分页(Cursor-based Pagination)代替 LIMIT offset, size,例如:

      sql 复制代码
      SELECT batch_id, COUNT(1) AS countAll, ...
      FROM ecif_point_subjects_info_2023
      WHERE batch_date = '2023-12-30' AND batch_id = '20231230803'
        AND (br_no, tx_br_no) > ('last_br_no', 'last_tx_br_no')
      GROUP BY br_no, tx_br_no
      ORDER BY br_no, tx_br_no
      LIMIT 5;
    • 每次查询使用上一次查询的最后一条记录的 br_notx_br_no 作为游标。

4. 缓存结果

  • 对于频繁查询的聚合结果,可以使用缓存(如 Redis)来减少数据库的负载。

5. 批量计算

  • 如果聚合结果用于报表展示,可以考虑在后台异步计算并存储结果,减少实时查询的压力。

五、总结

  • 当前查询性能瓶颈

    • 扫描行数大(约 138 万行)。
    • 深分页导致不必要的数据扫描。
    • 聚合操作增加 CPU 开销。
  • 优化方向

    • 优化索引,确保字段匹配。
    • 使用游标分页减少深分页带来的性能问题。
    • 缩小查询范围,减少扫描行数。
    • 使用缓存或异步计算减少实时查询压力。

通过以上优化措施,可以显著提升查询性能,尤其是在大数据量和高并发场景下。

相关推荐
AI 嗯啦2 小时前
SQL详细语法教程(三)mysql的函数知识
android·开发语言·数据库·python·sql·mysql
杰克尼4 小时前
mysql-条件查询案例
数据库·mysql
你那是什么调调6 小时前
`SHOW PROCESSLIST;` 返回列详解(含义 + 单位)
mysql
云心雨禅7 小时前
网站突然崩了,此站点遇到了致命错误!
服务器·mysql
Menior_10 小时前
【补充】数据库中有关系统编码和校验规则的简述
数据库·mysql·oracle
Kay_Liang11 小时前
从聚合到透视:SQL 窗口函数的系统解读
大数据·数据库·sql·mysql·数据分析·窗口函数
诺亚凹凸曼13 小时前
MySQLinnodb引擎普通索引和唯一索引的区别
数据库·mysql
星空下的曙光16 小时前
MySQL → SQL → DDL → 表操作 → 数据类型 知识链整理成一份系统的内容
数据库·sql·mysql
小志的博客20 小时前
mysql——count(*)、count(1)和count(字段)谁更快?有什么区别?
mysql
三体世界1 天前
Mysql基本使用语句(一)
linux·开发语言·数据库·c++·sql·mysql·主键