PostgreSQL SQL 优化指南 四句真言(SQL 优化系列 1)
❝开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,可以解决你的问题。加群请联系 liuaustin3 ,(共3300人左右 1 + 2 + 3 + 4 +5 + 6 + 7 + 8 +9)(1 2 3 4 5 6 7群均已爆满,开8群近400 9群 200+,开10群PolarDB专业学习群100+)
暑期过去了,该干正事了。DBA其中的重要工作,SQL优化,至少到目前为止,这个工作还存在。以后这个工作有没有不好说,随着AI的能力的爆发,这个工作被替代也是在时间表上的事情了。
所以搞一个系列,数据库SQL和查询语句优化系列,纪念可能逝去的需求。今天先拿PG开刀,优化SQL的根本是提高单位时间SQL运行的个数,减少SQL运行期间可能触发的锁冲突,降低单位时间数据库CPU,IOPS,内存的消耗。
所以从一个SQL优化的角度上,如果光强调SQL执行的时间快与慢,那就太单纯了。
这里有一个四句真言
减少IO全扫描,合理利用“小”索引,
降低芯片计算量,减少无效排序与哈希,
提高并发与吞吐,避免大锁的冲突,
稳定执行的计划,数量大小都稳定。
PG 的优化和其他数据库相比,更加的复杂和多变。
复杂在哪里?
索引的多变,数据表状态的多变,factor 表的设置初始的多变,与并行的使用与优化。
1 索引的复杂和多变
PG的索引不光是常见的,B-TREE类型的索引,或者形式上的覆盖索引,主键,唯一索引,复合索引等等,PG的索引类型很多,如BRIN,BLOOM,GIN ,Gist等,熟悉多种索引的使用场景,建立合适的索引类型,也是PG DBA需要只晓得知识,因为其他的数据库类型没有这块功能,这就导致大部分其他DBA都忽略了 PG的这块能力和优化的手段。
举例,大量的时间数据的查询建立索引,可以考虑Brin索引的超大表,Brin比Btree索引要小几十倍,甚至上百倍。虽然查询速度上会变慢,但存储和内存的节省也是一种SQL的优化。如你以前使用 BTREE索引查询的时间是 0.01秒,而通过BRIN索引后,查询时间是0.1秒,但索引大小小了100倍,索引大小从50G 变成50MB,这样的优化也算是SQL的一种优化。
2 表factor的初始化设置
这点很少人提到过,这也是其他数据库DBA不具有的知识。在SQL优化中,我们希望我们提取的数据的空间是连续的,PG的原理大家也都理解,由于这个问题,很容易导致频繁UPDATE的表的数据看似应该连续的,却四分五裂。提取数据会导致机械磁盘的磁头频繁的移动,导致物理性的慢,所以PG的数据库建议还是上SSD更好,这里可以通过在建表的时候降低factor的比率,提高SQL在读取连续数据时的速度。
3 降低无效CPU的消耗
这里假设一个例子:
EXPLAIN (ANALYZE, BUFFERS)
SELECT customer_id, SUM(amount)
FROM orders
WHERE amount > 100
GROUP BY customer_id
ORDER BY SUM(amount) DESC
LIMIT 10;
GroupAggregate (cost=10000..20000 rows=1000 width=40)
(actual time=1200.500..1500.200 rows=10 loops=1)
Group Key: customer_id
-> Sort (cost=10000..12000 rows=100000 width=40)
(actual time=1190.100..1350.400 rows=1000000 loops=1)
Sort Key: customer_id
Sort Method: quicksort Memory: 120MB
Buffers: shared hit=200000 read=50000
-> Seq Scan on orders (cost=0..8000 rows=1000000 width=40)
(actual time=0.020..300.150 rows=1000000 loops=1)
Filter: (amount > 100)
Rows Removed by Filter: 200000
Planning Time: 0.100 ms
Execution Time: 1502.003 ms
在查询中,很容易看到第一个问题,全表扫描添加索引,但排序在这里也是一个消耗CPU的点,建立索引我会把索引建立成
CREATE INDEX idx_orders_customer_amount ON orders(customer_id, amount);
有人会问为什么不是
CREATE INDEX idx_orders_customer_amount ON orders(amount,customer_id,);
在这条语句里面包含了分组,分组的机制中就天然包含了排序,将customer_id放到前面,可以有效的进行有序扫描amount > 100的数据扫描,最后拿出的数据也是就满足了分组中的排序需求。
另外还有一个关键点,这里也是希望AI目前无法涉及到的点,DBA的经验。岁数大的DBA都明白,业务逻辑是优化SQL的核心之一,customer_id 和 amount 在其他SQL的查询方式,大脚豆都能想出来,所以问出为什么amount不在复合索引前的,你的经验还是嫩了点,俗称你是一根筋。
4 制造稳定性的执行计划,而不是不稳定的执行计划
我们还以一个实例来说明
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM orders
WHERE customer_id = 123
AND amount > 1000;
稳定的索引,制造稳定的执行计划。
CREATE INDEX idx_orders_customer_amount ON orders(customer_id);
CREATE INDEX idx_orders_customer_amount ON orders(amount);
不稳定的索引,制造不稳定的执行计划
CREATE INDEX idx_orders_customer_amount ON orders( amount,customer_id);
上面两个索引建立的方式,从稳定性上讲,第一个索引会让执行计划更加稳定,而第二个索引有一定可能性产生问题,通常amount是一个忽大忽小的量,一个客户可能有amount很大的情况,导致行数过多,那么就会导致执行计划放弃索引直接走全表扫描。所以第一个索引建立的时候考虑到这个问题。
那么这里又引出第二个问题,到底我是建立复合索引还是单个多个索引,大部分情况下,我们建议有效的复合索引,有效的复合索引会降低PG在使用多个单个索引处理查询时,使用bitmap index scan 将多个单独的索引合并走交集的情况,这样的方式会消耗CPU,不如复合索引。
所以评估稳定性的问题,还需要考虑你大部分查询的语句的查询情况和查询频率后,才能找到索引建立的更优方案。
至于PG的并行查询,在我们的经验中,一般的设置都不会针对每个SQL超过 4个并行。
PG SQL的优化一篇文章是无法说完整的,SQL的优化也是要凭借对业务的更多了解和之前SQL优化的经验。
但这里需要注意,PG更多的SQL优化在于非SQL本身的一些优化点,而那些优化点是其他的数据库不具有的经验常识。
PostgreSQL SQL 优化要点总结表
| 1. 索引的复杂和多变 | - 文本搜索 → GIN/GiST - 常规点查 → B-TREE | ||
| 2. 表 fillfactor 的初始化设置 | - 让数据连续,减少磁盘随机 IO | ||
| 3. 降低无效 CPU 消耗 | GROUP BY + ORDER BY- 索引写成 (customer_id, amount) 而不是 (amount, customer_id)- 保证分组和排序自然有序 | ||
| 4. 稳定执行计划 | (customer_id) 更稳定- (amount, customer_id) 在 amount 值分布大时不稳定,可能导致全表扫描 | ||
| 5. 单索引 vs. 复合索引 | - 合理复合索引 → 更优执行 | ||
| 6. 并行查询 | - 但需注意资源竞争 | ||
| 7. LIMIT 语句优化 | - 避免 LIMIT offset,N 大偏移,推荐 keyset pagination(基于索引游标翻页) | ||
| 8. 多表 JOIN 优化 | - 小表驱动大表(Nested Loop 效果更佳) - 使用 EXPLAIN 检查是否出现 Hash Join 的内存溢出 |
微软动手了,联合OpenAI + Azure 云争夺AI服务市场
“当复杂的SQL不再需要特别的优化”,邪修研究PolarDB for PG 列式索引加速复杂SQL运行
“合体吧兄弟们!”——从浪浪山小妖怪看OceanBase国产芯片优化《OceanBase “重如尘埃”之歌》
未知黑客通过SQL SERVER 窃取企业SAP核心数据,影响企业运营
那个MySQL大事务比你稳定,主从延迟低,为什么? Look my eyes! 因为宋利兵宋老师
非“厂商广告”的PolarDB课程:用户共创的新式学习范本--7位同学获奖PolarDB学习之星
说我PG Freezing Boom 讲的一般的那个同学,专帖给你,看看这次可满意
这个 PostgreSQL 让我有资本找老板要 鸡腿 鸭腿 !!
OceanBase Hybrid search 能力测试,平换MySQL的好选择
HyBrid Search 实现价值落地,从真实企业的需求角度分析 !不只谈技术!
OceanBase 光速快递 OB Cloud “MySQL” 给我,Thanks a lot
从“小偷”开始,不会从“强盗”结束 -- IvorySQL 2025 PostgreSQL 生态大会
被骂后的文字--技术人不脱离思维困局,终局是个 “死” ? ! ......
个群2025上半年总结,OB、PolarDB, DBdoctor、爱可生、pigsty、osyun、工作岗位等
从MySQL不行了,到乙方DBA 给狗,狗都不干? 我干呀!
SQL SERVER 2025发布了, China幸亏有信创!
MongoDB 麻烦专业点,不懂可以问,别这么用行吗 ! --TTL
PostgreSQL 新版本就一定好--由培训现象让我做的实验
删除数据“八扇屏” 之 锦门英豪 --我去-BigData!
写了3750万字的我,在2000字的OB白皮书上了一课--记 《OceanBase 社区版在泛互场景的应用案例研究》
跟我学OceanBase4.0 --阅读白皮书 (OB分布式优化哪里了提高了速度)
跟我学OceanBase4.0 --阅读白皮书 (4.0优化的核心点是什么)
跟我学OceanBase4.0 --阅读白皮书 (0.5-4.0的架构与之前架构特点)
跟我学OceanBase4.0 --阅读白皮书 (旧的概念害死人呀,更新知识和理念)
MongoDB 相关文章
MongoDB “升级项目” 大型连续剧(4)-- 与开发和架构沟通与扫尾
MongoDB “升级项目” 大型连续剧(3)-- 自动校对代码与注意事项
MongoDB “升级项目” 大型连续剧(2)-- 到底谁是"der"
MongoDB “升级项目” 大型连续剧(1)-- 可“生”可不升
MongoDB 大俗大雅,上来问分片真三俗 -- 4 分什么分
MongoDB 大俗大雅,高端知识讲“庸俗” --3 奇葩数据更新方法
MongoDB 大俗大雅,高端的知识讲“通俗” -- 2 嵌套和引用
MongoDB 大俗大雅,高端的知识讲“低俗” -- 1 什么叫多模
MongoDB 合作考试报销活动 贴附属,MongoDB基础知识速通
MongoDB 使用网上妙招,直接DOWN机---清理表碎片导致的灾祸 (送书活动结束)
MongoDB 2023年度纽约 MongoDB 年度大会话题 -- MongoDB 数据模式与建模
免费PolarDB云原生课程,听课“争”礼品,重塑云上知识,提高专业能力
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
POLARDB 添加字段 “卡” 住---这锅Polar不背
PolarDB 版本差异分析--外人不知道的秘密(谁是绵羊,谁是怪兽)
PolarDB 答题拿-- 飞刀总的书、同款卫衣、T恤,来自杭州的Package(活动结束了)
PolarDB for MySQL 三大核心之一POLARFS 今天扒开它--- 嘛是火
PostgreSQL 无服务 Neon and Aurora 新技术下的新经济模式 (翻译)
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
全世界都在“搞” PostgreSQL ,从Oracle 得到一个“馊主意”开始
PostgreSQL 加索引系统OOM 怨我了--- 不怨你怨谁
PostgreSQL “我怎么就连个数据库都不会建?” --- 你还真不会!
PostgreSQL 稳定性平台 PG中文社区大会--杭州来去匆匆
PostgreSQL 分组查询可以不进行全表扫描吗?速度提高上千倍?
POSTGRESQL --Austindatabaes 历年文章整理
PostgreSQL 查询语句开发写不好是必然,不是PG的锅
MySQL相关文章