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

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

问题概述

看如下 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

相关推荐
苦逼的猿宝3 小时前
基于springboot的社区团购系统设计(源码+论文)
java·毕业设计·springboot·计算机毕业设计
电魂泡哥3 小时前
RocketMQ Dledger 集群与 Raft 协议
java·rocketmq·java-rocketmq
行走的蜗牛3 小时前
【springai】 Model层设计与实现
java·ai编程
難釋懷3 小时前
Redis内存回收-过期key处理
数据库·redis·缓存
KaMeidebaby3 小时前
卡梅德生物技术快报|PROTAC 药物降解蛋白原理及数据库平台开发全流程
前端·数据库·其他·百度·新浪微博
认真的薛薛3 小时前
Linux基础:GitOps发布流程
java·linux·运维
鱼鳞_3 小时前
苍穹外卖-Day05(Redis)
java·redis
雨落在了我的手上3 小时前
初识java(九):类和对象(⼀)
java·开发语言