高斯性能分析【第一天】单表执行计划分析

高斯性能分析【第一天】单表执行计划分析

问题概述

看如下 SQL 执行计划,回答:

  1. 是否是 Seq Scan?
  2. 扫描了多少行?
  3. 返回了多少行?
  4. Filter 过滤掉了多少数据?
sql 复制代码
testdb=> explain analyze select * from lab_order where user_id = 10001;
 id |         operation         | A-time | A-rows | E-rows | Peak Memory | A-width | E-width |     E-costs     
----+---------------------------+--------+--------+--------+-------------+---------+---------+-----------------
  1 | ->  Seq Scan on lab_order | 55.754 |      6 |      6 | 53KB        |         |      65 | 0.000..7170.000
(1 row)

 Predicate Information (identified by plan id) 
-----------------------------------------------
   1 --Seq Scan on lab_order
         Filter: (user_id = 10001)
         Rows Removed by Filter: 299994
(3 rows)

       ====== Query Summary =====       
----------------------------------------
 Datanode executor start time: 0.070 ms
 Datanode executor run time: 56.977 ms
 Datanode executor end time: 0.014 ms
 Planner runtime: 0.721 ms
 Query Id: 1948651263768123007
 Total runtime: 57.076 ms
(6 rows)

testdb=> 

分析

根据 EXPLAIN ANALYZE 输出:

  1. 是否是 Seq Scan?

    是的,操作行显示:Seq Scan on lab_order,说明对表 lab_order 进行了顺序扫描。

  2. 扫描了多少行?

    Seq Scan 实际扫描了 6 + 299,994 = 300,000 行(返回的行 + 被过滤掉的行)。

    更直接地看 Rows Removed by Filter: 299994,说明原始表中有 300,000 行被扫描。

  3. 返回了多少行?

    返回了 6 行,A-rows | 6

  4. Filter 过滤掉了多少数据?

    Filter 过滤掉了 299,994 行,正如 Rows Removed by Filter: 299994 所示。

简单总结:数据库做了全表扫描(Seq Scan),扫描了 30 万行,只返回 6 行,过滤掉了 299,994 行。

结论(优化建议)

这个查询 有很大优化空间。原因是:

  • lab_order 有大约 30 万行,你只根据 user_id = 10001 查询 6 行。
  • 现在是 Seq Scan(全表扫描),这意味着 数据库 会把整张表读一遍,然后过滤掉 299,994 行,效率低下。

1️⃣ 优化思路

使用索引

最直接的方法是为 user_id 建立索引,这样查询就可以直接定位到符合条件的行,而不需要全表扫描。

sql 复制代码
CREATE INDEX idx_lab_order_user_id ON lab_order(user_id);

效果

  • 查询会使用 Index ScanBitmap Index Scan ,只扫描匹配 user_id = 10001 的行,而不是整个表。
  • 对于这种返回行数非常少的情况,性能提升非常明显。

组合索引(可选)

实际业务上,如果查询除了 user_id 还有其他筛选条件或排序,可以创建 复合索引

sql 复制代码
CREATE INDEX idx_lab_order_user_id_status ON lab_order(user_id, status);
  • 适用于经常按 user_id + status 查询的场景。
  • 可以覆盖查询,减少回表操作。

考虑表分区(可选)

如果 lab_order 表非常大且 user_id 分布稀疏,可以考虑 按 user_id 分区

  • 对于查询某个用户的所有订单,这样可以只扫描对应分区。
  • 适合表超过几百万行或更多的场景。

检查统计信息

确保数据库中的表统计信息是最新的:

sql 复制代码
ANALYZE lab_order;
  • 数据库用统计信息决定是否使用索引,如果统计信息过旧,可能仍然选择 Seq Scan。

2️⃣ 预期效果

  • 使用索引后,查询 6 行的时间可能从 50ms 以上降到几毫秒
  • 避免了 299,994 行的无效扫描,节省了 CPU 和 I/O。

💡 小结

  • user_id 建索引 → 最直接有效。
  • 对经常联合查询的列可建复合索引 → 提升更多查询。
  • 保持统计信息最新 → 优化器选择最优执行计划。

验证

添加索引后的执行计划如下,

  • 添加索引前,耗时:Total runtime: 57.076 ms
  • 添加索引后,耗时:Total runtime: 0.284 ms
sql 复制代码
testdb=> CREATE INDEX idx_lab_order_user_id ON lab_order(user_id);
CREATE INDEX
testdb=> 
testdb=> 
testdb=> 
testdb=> 
testdb=> explain analyze select * from lab_order where user_id = 10001;
 id |                        operation                        | A-time | A-rows | E-rows | Peak Memory | A-width | E-width |   E-costs    
----+---------------------------------------------------------+--------+--------+--------+-------------+---------+---------+--------------
  1 | ->  Index Scan using idx_lab_order_user_id on lab_order | 0.173  |      6 |      6 | 85KB        |         |      65 | 0.000..7.909
(1 row)

       Predicate Information (identified by plan id)       
-----------------------------------------------------------
   1 --Index Scan using idx_lab_order_user_id on lab_order
         Index Cond: (user_id = 10001)
(2 rows)

       ====== Query Summary =====       
----------------------------------------
 Datanode executor start time: 0.040 ms
 Datanode executor run time: 0.226 ms
 Datanode executor end time: 0.009 ms
 Planner runtime: 1.365 ms
 Query Id: 1948651263768126756
 Total runtime: 0.284 ms
(6 rows)

 ====== Query Others ===== 
---------------------------
 Bypass: Yes
(1 row)

testdb=> 

若有转载,请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/161320999

相关推荐
liuxiaowei39 小时前
【绝版教程】新版MySQL DBA高级实战进阶班 MySQL8.0 姜承尧-腾讯数据库总监
数据库·mysql·dba
维天说10 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
破碎的南瓜10 小时前
sqli--sql注入过关笔记(1,2,3,4,5,9)
数据库·笔记·sql
Zane199410 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
噢,我明白了11 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品11 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘11 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
SelectDB11 小时前
Apache Doris Variant 动态 JSON 实战教程:从建表到跑通 100M Agent 日志查询
数据库
Java内核笔记12 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
sg_knight12 小时前
MySQL 存储过程详解:从入门到实战
android·数据库·mysql·database·dba·关系型数据库·db