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

sql表结构和执行计划

mysql 复制代码
-- --------------------------------------------------------------------------
-- table structure
-- --------------------------------------------------------------------------
| ecif_point_subjects_info_2023 | CREATE TABLE `ecif_point_subjects_info_2023` (
  `id` varchar(32) NOT NULL COMMENT '主键ID',
  `batch_id` varchar(32) NOT NULL COMMENT '批量id',
  `batch_date` varchar(20) NOT NULL COMMENT '批量日期',
  `br_no` varchar(128) NOT NULL COMMENT '法人机构',
  `tx_br_no` varchar(32) NOT NULL COMMENT '交易机构',
  `dept_no` varchar(32) DEFAULT NULL COMMENT '条线(部门)',
  `subject_no` varchar(32) NOT NULL COMMENT '科目编号',
  `subject_name` varchar(64) DEFAULT NULL COMMENT '科目名称',
  `bal_ind` varchar(8) DEFAULT NULL COMMENT '余额方向1 借 2 贷 0 双向',
  `debt_total_amt` decimal(16,2) DEFAULT NULL COMMENT '借发生额',
  `crdt_total_amt` decimal(16,2) DEFAULT NULL COMMENT '贷发生额',
  `adjust_flag` varchar(4) NOT NULL DEFAULT 'N' COMMENT '手工调账科目标识 Y  是手工调账 N  不是手工调账科目 默认N',
  `create_time` varchar(20) DEFAULT NULL COMMENT '创建时间',
  `modify_time` varchar(20) DEFAULT NULL COMMENT '结束时间',
  `field1` varchar(128) DEFAULT NULL COMMENT '扩展1',
  `field2` varchar(128) DEFAULT NULL COMMENT '扩展2',
  PRIMARY KEY (`id`,`batch_date`) USING BTREE,
  KEY `ecif_point_subjects_info_idx2` (`batch_date`,`batch_id`,`br_no`,`tx_br_no`,`debt_total_amt`,`crdt_total_amt`),
  KEY `ecif_point_subjects_info_idx3` (`batch_date`,`batch_id`,`br_no`,`tx_br_no`,`dept_no`,`field2`,`bal_ind`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='积分供数科目表min'
/*!50500 PARTITION BY RANGE  COLUMNS(batch_date)
(PARTITION p202301 VALUES LESS THAN ('2023-02-01') COMMENT = '2023年01月份数据' ENGINE = InnoDB,
 PARTITION p202302 VALUES LESS THAN ('2023-03-01') COMMENT = '2023年02月份数据' ENGINE = InnoDB,
 PARTITION p202303 VALUES LESS THAN ('2023-04-01') COMMENT = '2023年03月份数据' ENGINE = InnoDB,
 PARTITION p202304 VALUES LESS THAN ('2023-05-01') COMMENT = '2023年04月份数据' ENGINE = InnoDB,
 PARTITION p202305 VALUES LESS THAN ('2023-06-01') COMMENT = '2023年05月份数据' ENGINE = InnoDB,
 PARTITION p202306 VALUES LESS THAN ('2023-07-01') COMMENT = '2023年06月份数据' ENGINE = InnoDB,
 PARTITION p202307 VALUES LESS THAN ('2023-08-01') COMMENT = '2023年07月份数据' ENGINE = InnoDB,
 PARTITION p202308 VALUES LESS THAN ('2023-09-01') COMMENT = '2023年08月份数据' ENGINE = InnoDB,
 PARTITION p202309 VALUES LESS THAN ('2023-10-01') COMMENT = '2023年09月份数据' ENGINE = InnoDB,
 PARTITION p202310 VALUES LESS THAN ('2023-11-01') COMMENT = '2023年10月份数据' ENGINE = InnoDB,
 PARTITION p202311 VALUES LESS THAN ('2023-12-01') COMMENT = '2023年11月份数据' ENGINE = InnoDB,
 PARTITION p202312 VALUES LESS THAN ('2024-01-01') COMMENT = '2023年12月份数据' ENGINE = InnoDB) */ |

-- --------------------------------------------------------------------------
-- explain
-- --------------------------------------------------------------------------
mysql> EXPLAIN
SELECT * FROM ecif_point_subjects_info_2023 
WHERE batch_date = '2023-12-30' AND batch_id = '20231230803'
ORDER BY br_no ASC , tx_br_no ASC , dept_no ASC , field2 ASC , bal_ind ASC 
LIMIT 500000,5;
+----+-------------+-------------------------------+------------+------+-------------------------------------------------------------+-------------------------------+---------+-------------+---------+----------+-------+
| 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_idx3 | 212     | const,const | 1200102 |   100.00 | NULL  |
+----+-------------+-------------------------------+------------+------+-------------------------------------------------------------+-------------------------------+---------+-------------+---------+----------+-------+
1 row in set (0.05 sec)

mysql> EXPLAIN FORMAT=TREE
SELECT * FROM ecif_point_subjects_info_2023 
WHERE batch_date = '2023-12-30' AND batch_id = '20231230803'
ORDER BY br_no ASC , tx_br_no ASC , dept_no ASC , field2 ASC , bal_ind ASC 
LIMIT 500000,5;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Limit/Offset: 5/500000 row(s)  (cost=300076.70 rows=5)
    -> Index lookup on ecif_point_subjects_info_2023 using ecif_point_subjects_info_idx3 (batch_date='2023-12-30', batch_id='20231230803')  (cost=300076.70 rows=1200102)
 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.04 sec)

SQL执行计划分析

1. 执行计划表头信息

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_idx3 | 212     | const,const | 1200102 |   100.00 | NULL  |
+----+-------------+-------------------------------+------------+------+-------------------------------------------------------------+-------------------------------+---------+-------------+---------+----------+-------+
各列含义分析:
  • 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_idx3 是实际使用的索引。
  • key_len :使用的索引长度。212 字节,这表明索引包含了多个字段(batch_date, batch_id, br_no, tx_br_no, dept_no, field2, bal_ind)。
  • ref :显示索引的哪一列被使用。const,const 表示 batch_datebatch_id 被用作常量值进行查询。
  • rows :MySQL 估计需要扫描的行数。1200102 表示 MySQL 估计需要扫描大约 120 万行数据。
  • filtered :表示查询条件过滤后的行数比例。100.00 表示没有进一步的过滤。
  • Extra :额外的信息。NULL 表示没有额外的操作。

2. 执行计划的树状结构分析

plaintext 复制代码
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Limit/Offset: 5/500000 row(s)  (cost=300076.70 rows=5)
    -> Index lookup on ecif_point_subjects_info_2023 using ecif_point_subjects_info_idx3 (batch_date='2023-12-30', batch_id='20231230803')  (cost=300076.70 rows=1200102)
 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
各部分含义分析:
  • Limit/Offset :表示查询结果将被限制为从第 500,000 行开始,返回 5 行数据。cost=300076.70 表示执行该操作的成本,rows=5 表示最终返回的行数。
  • Index lookup :表示 MySQL 使用索引 ecif_point_subjects_info_idx3 进行查找。索引字段包括 batch_date, batch_id, br_no, tx_br_no, dept_no, field2, bal_ind

3. 性能分析

  1. 索引选择

    • 查询使用了 ecif_point_subjects_info_idx3 索引,这是一个复合索引,包含了 batch_date, batch_id, br_no, tx_br_no, dept_no, field2, bal_ind 字段。
    • 由于查询条件中使用了 batch_datebatch_id,MySQL 能够快速定位到特定的分区和数据范围。
  2. 数据扫描量

    • 预计需要扫描 120 万行数据,这可能是因为查询条件虽然精确,但排序和分页操作导致 MySQL 需要扫描大量数据以找到所需的 5 行。
  3. 分页问题

    • 使用 LIMIT 500000, 5 导致 MySQL 需要扫描前 500,000 行数据,然后丢弃这些数据,只返回最后 5 行。这种分页方式在大数据量下效率较低。
  4. 优化建议

    • 减少扫描行数:可以通过优化查询条件或增加索引来减少需要扫描的行数。
    • 避免深分页:如果不需要深分页,可以考虑其他分页策略,如使用游标分页。
    • 索引优化:确保索引字段与查询条件和排序字段匹配,以减少排序和扫描的开销。

4. 总结

  • 查询效率:当前查询需要扫描大量数据(约 120 万行),并且使用了深分页,导致性能较低。
  • 优化方向:优化索引、减少扫描行数、避免深分页。
  • 建议:考虑使用游标分页或其他分页策略,以提高查询效率。同时,确保索引字段与查询条件和排序字段匹配,以减少排序和扫描的开销。
相关推荐
麦聪聊数据6 小时前
MySQL并发与锁:从“防止超卖”到排查“死锁”
数据库·sql·mysql
myzshare8 小时前
实战分享:我是如何用SSM框架开发出一个完整项目的
java·mysql·spring cloud·微信小程序
辞砚技术录9 小时前
MySQL面试题——索引2nd
数据库·mysql·面试
墨笔之风9 小时前
java后端根据双数据源进行不同的接口查询
java·开发语言·mysql·postgres
黑白极客10 小时前
怎么给字符串字段加索引?日志系统 一条更新语句是怎么执行的
java·数据库·sql·mysql·引擎
哈里谢顿11 小时前
小探mysql覆盖索引
mysql
X***078811 小时前
理解 MySQL 的索引设计逻辑:从数据结构到实际查询性能的系统分析
数据库·mysql·sqlite
warton8811 小时前
ubuntu24 安装 proxsql 实现数据库代理
linux·运维·mysql·ubuntu
天意pt11 小时前
Blog-SSR 系统操作手册(v1.0.0)
前端·vue.js·redis·mysql·docker·node.js·express
麦麦大数据12 小时前
J009 美食推荐可视化大数据系统vue+springboot
vue.js·spring boot·mysql·推荐算法·美食·可视化分析·沙箱支付