PG优化系列:Oracle迁移到PG中性能下降1000倍续集

news/2025/11/20 16:18:30/文章来源:https://www.cnblogs.com/www-htz-pw/p/19247533

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
由于博客中有大量代码,通过页面浏览效果更佳。

在上一篇文章提到朋友他们小系统从Oracle迁移到PG中性能下降1000倍的案例中提到在PG环境中not in无法自动改写为反连接的方式,此时需要手动的将SQL语句重写为not exists后,PG优化器才能自动改写为反连接方式。其中PG大佬留言分享了在PG17版本中引入新特性《允许将相关的 IN 子查询转换为连接》,非常感谢大佬的关注和分享。此时了解到PG17引入的这个新功能,这个功能是真的好,弥补了在之前老版本中只能转换简单的IN子查询的缺陷,此功能可以大大减少对开发人员SQL能力要求和提升Oracle迁移到PG的兼容性,但是非常遗憾的是此功能还无法用于not in场景环境中。

下面简单在17版本中测试此功能,看看表现如何。

测试环境还是利用的postgres_air这个测试环境。

1 NOT IN 是否转换

继续使用上篇中提到的SQL语句。

htz=# explain select count(*) from booking a where a.account_id not in (select b.account_id from account b);QUERY PLAN                                             
----------------------------------------------------------------------------------------------------Finalize Aggregate  (cost=43138248424.04..43138248424.05 rows=1 width=8)->  Gather  (cost=43138248423.82..43138248424.03 rows=2 width=8)Workers Planned: 2->  Partial Aggregate  (cost=43138247423.82..43138247423.83 rows=1 width=8)->  Parallel Seq Scan on booking a  (cost=0.00..43138244322.60 rows=1240490 width=0)Filter: (NOT (ANY (account_id = (SubPlan 1).col1)))SubPlan 1->  Materialize  (cost=0.00..31970.50 rows=1121833 width=4)->  Seq Scan on account b  (cost=0.00..21978.33 rows=1121833 width=4)
(9 rows)

在执行计划中注意到关键词SubPlan 1,所以这里说明在NOT IN这样的场景中还是无法做到自动转换,期待PG在未来的版本中新增NOT IN的转换功能。

2 IN的转换

通过查阅官方给出的文档(https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=9f1337639)可以得到在PG 17之前的版本有如下的限制:

  • 子链接只能被拉取为子查询
  • 无法处理varlevelsup=1的变量引用
  • 缺乏lateral join的支持能力

那在17的版本中,怎么知道数据库进行了重新呢?除了执行计划外,还可以通过参数debug_print_rewritten,此参数是一个用于调试的参数,其作用是 打印查询在经过重写规则(rewrite rules)处理之后的内部表示。

2.1 拉取ANY_subquery的语句

测试SQL语句:
EXPLAIN (COSTS OFF, ANALYZE)
SELECT o.order_id, o.customer_id, o.total_amount
FROM test_orders o
WHERE o.order_id IN (SELECT oi.order_id FROM test_order_items oi WHERE oi.product_id IN (SELECT p.product_id FROM test_products p WHERE p.category = '手机' AND p.price > o.total_amount)
);

在PG17中执行计划:

                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------Nested Loop Semi Join (actual time=0.158..0.159 rows=0 loops=1)->  Seq Scan on test_orders o (actual time=0.012..0.013 rows=10 loops=1)->  Subquery Scan on "ANY_subquery" (actual time=0.014..0.014 rows=0 loops=10)Filter: ((o.order_id)::text = ("ANY_subquery".order_id)::text)Rows Removed by Filter: 1->  Nested Loop (actual time=0.011..0.014 rows=1 loops=10)->  Index Scan using idx_products_category on test_products p (actual time=0.005..0.006 rows=1 loops=10)Index Cond: ((category)::text = '手机'::text)Filter: (price > o.total_amount)Rows Removed by Filter: 2->  Bitmap Heap Scan on test_order_items oi (actual time=0.005..0.005 rows=1 loops=11)Recheck Cond: ((product_id)::text = (p.product_id)::text)Heap Blocks: exact=9->  Bitmap Index Scan on idx_order_items_product_id (actual time=0.003..0.003 rows=1 loops=11)Index Cond: ((product_id)::text = (p.product_id)::text)Planning Time: 1.820 msExecution Time: 0.242 ms
(17 rows)

在PG17的执行计划中,已经看不到SubPlan的关键词,也就说明子查询重写了。

在PG 14中执行计划:

                                                     QUERY PLAN                                                     
--------------------------------------------------------------------------------------------------------------------Seq Scan on test_orders o (actual time=0.076..0.076 rows=0 loops=1)Filter: (SubPlan 1)Rows Removed by Filter: 10SubPlan 1->  Nested Loop (actual time=0.005..0.007 rows=1 loops=10)->  Index Scan using idx_products_category on test_products p (actual time=0.003..0.003 rows=1 loops=10)Index Cond: ((category)::text = '手机'::text)Filter: (price > o.total_amount)Rows Removed by Filter: 2->  Bitmap Heap Scan on test_order_items oi (actual time=0.002..0.002 rows=1 loops=11)Recheck Cond: ((product_id)::text = (p.product_id)::text)Heap Blocks: exact=9->  Bitmap Index Scan on idx_order_items_product_id (actual time=0.002..0.002 rows=1 loops=11)Index Cond: ((product_id)::text = (p.product_id)::text)Planning Time: 0.471 msExecution Time: 0.144 ms
(16 rows)

这里可以看到SubPlan的关键词。

2.2 多层嵌套

EXPLAIN (COSTS OFF, ANALYZE)
SELECT c.customer_name, p.product_name, p.price
FROM test_customers c
INNER JOIN test_products p ON p.product_id IN (SELECT oi.product_id FROM test_order_items oi WHERE oi.order_id IN (SELECT o.order_id FROM test_orders o WHERE o.customer_id = c.customer_idAND o.order_status = 'completed')
)
WHERE c.customer_type = 'P';

在PG 17中的执行计划:

                                                            QUERY PLAN                                                            
----------------------------------------------------------------------------------------------------------------------------------Nested Loop (actual time=0.127..0.139 rows=3 loops=1)->  Bitmap Heap Scan on test_customers c (actual time=0.046..0.046 rows=3 loops=1)Recheck Cond: (customer_type = 'P'::bpchar)Heap Blocks: exact=1->  Bitmap Index Scan on idx_customers_type (actual time=0.027..0.027 rows=3 loops=1)Index Cond: (customer_type = 'P'::bpchar)->  Nested Loop (actual time=0.029..0.030 rows=1 loops=3)->  HashAggregate (actual time=0.021..0.021 rows=1 loops=3)Group Key: ("ANY_subquery".product_id)::textBatches: 1  Memory Usage: 24kB->  Subquery Scan on "ANY_subquery" (actual time=0.017..0.019 rows=1 loops=3)->  Nested Loop (actual time=0.016..0.018 rows=1 loops=3)->  Bitmap Heap Scan on test_orders o (actual time=0.010..0.010 rows=1 loops=3)Recheck Cond: ((customer_id)::text = (c.customer_id)::text)Filter: ((order_status)::text = 'completed'::text)Heap Blocks: exact=2->  Bitmap Index Scan on idx_orders_customer_date (actual time=0.006..0.006 rows=1 loops=3)Index Cond: ((customer_id)::text = (c.customer_id)::text)->  Bitmap Heap Scan on test_order_items oi (actual time=0.006..0.006 rows=1 loops=3)Recheck Cond: ((order_id)::text = (o.order_id)::text)Heap Blocks: exact=3->  Bitmap Index Scan on idx_order_items_order_product (actual time=0.003..0.003 rows=1 loops=3)Index Cond: ((order_id)::text = (o.order_id)::text)->  Index Scan using test_products_pkey on test_products p (actual time=0.008..0.008 rows=1 loops=3)Index Cond: ((product_id)::text = ("ANY_subquery".product_id)::text)Planning Time: 0.594 msExecution Time: 0.293 ms
(27 rows)

在PG 14中的执行计划。

                                                     QUERY PLAN                                                      
---------------------------------------------------------------------------------------------------------------------Nested Loop (actual time=0.104..0.208 rows=3 loops=1)Join Filter: (SubPlan 1)Rows Removed by Join Filter: 27->  Seq Scan on test_products p (actual time=0.020..0.022 rows=10 loops=1)->  Materialize (actual time=0.003..0.003 rows=3 loops=10)->  Bitmap Heap Scan on test_customers c (actual time=0.021..0.022 rows=3 loops=1)Recheck Cond: (customer_type = 'P'::bpchar)Heap Blocks: exact=1->  Bitmap Index Scan on idx_customers_type (actual time=0.012..0.012 rows=3 loops=1)Index Cond: (customer_type = 'P'::bpchar)SubPlan 1->  Nested Loop (actual time=0.004..0.005 rows=1 loops=30)->  Index Scan using idx_orders_customer_date on test_orders o (actual time=0.001..0.002 rows=1 loops=30)Index Cond: ((customer_id)::text = (c.customer_id)::text)Filter: ((order_status)::text = 'completed'::text)->  Bitmap Heap Scan on test_order_items oi (actual time=0.002..0.002 rows=1 loops=29)Recheck Cond: ((order_id)::text = (o.order_id)::text)Heap Blocks: exact=29->  Bitmap Index Scan on idx_order_items_order_product (actual time=0.001..0.001 rows=1 loops=29)Index Cond: ((order_id)::text = (o.order_id)::text)Planning Time: 1.657 msExecution Time: 0.307 ms
(22 rows)

3 总结

通过上面的列子,可以知道PG17新版本中引入的IN转换的功能可以很好的对IN子查询的进行自动转换,弥补了之前版本中只能转换简单的IN子查询,期待PG未来的版本在优化器上能够更加的完善。

------------------作者介绍-----------------------
姓名:黄廷忠
个人博客: (http://www.htz.pw)
CSDN地址: (https://blog.csdn.net/wwwhtzpw)
博客园地址: (https://www.cnblogs.com/www-htz-pw)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/971145.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ORACLE故障恢复:启用与禁用事务的并行恢复

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。ORACLE故障恢…

基于SIC8F1233开发智能充气泵方案

方案概述​本充气泵方案采用SIC8833芯片作为主控芯片,该芯片内置8k16位ROM程序存储器,内置128字节程序EEPROM,可重复擦写1万次,具有12位高精度ADC,能实现高精度的压力测量与控制,可满足多种场景下的充气需求。方…

ESD整改核心思路:堵、防、疏的实践平衡-ASIM阿赛姆

一、USB接口整改典型路径 LED灯条控制器在USB接口4kV接触放电测试中出现灯灭需断电恢复。初步排查发现已安装三颗ESD抑制器,但金属外壳与系统地间串联电容形成隔离。去掉电容并直接短接后,测试通过率提升至80%。进一…

2025 最新瓷砖品牌权威推荐:经国际协会测评认证,精选品质与创新兼具的优质品牌

引言 随着全球家居消费升级与绿色低碳理念普及,瓷砖行业的品质竞争与创新变革愈发激烈。市场上产品同质化、环保标准参差不齐等问题,让消费者与采购方难以精准抉择。本次推荐榜单依托国际陶瓷协会(ICT)最新测评体系…

Qiling使用速记

Qiling 参考文献 官方网站:https://qiling.io/ 文档:https://docs.qiling.io/en/latest/ 相关信息集合:https://github.com/qilingframework/qiling/issues/134 练习用:https://www.shielder.com/blog/2021/07/qil…

保温杯LED屏幕驱动和语音播报二合一芯片方案

又和大家见面了这一次,我们要聊的不是那些高大上的半导体设备,而是一个与我们日常生活息息相关的小物件——智能保温杯。你可能会好奇,保温杯不就是个装水的容器吗,能有多智能?别急,当我们把一颗小小的语音芯片装…

B端界面设计之流程页设计——从“能用”到“好用”的边界重构

B端界面设计之流程页设计——从“能用”到“好用”的边界重构在兰亭妙微的培训中常被提及:“B端流程页的终极考验,不是步骤的完整度,而是在业务边界内实现效率最大化。”这一观点与行业内“B端设计以效率为底线”的…

2025 靠谱初中一对一辅导机构排行榜:权威评价 + 真实口碑排名推荐

初中阶段既是学业爬坡期,更是中考冲刺的关键节点,家长为孩子挑选一对一机构时,满是两难:孩子功课难度骤增,急需贴合中考考点的针对性辅导;可补习市场乱象频发,刷出来的 “好评榜单” 真假难辨,机构宣称的 “定…

什么是I2C通信协议

什么是I2C通信协议什么是I2C通信协议I2C是一种串行,同步,多主机,板对板,半双工通信协议。顾名思义,它主要用在PCB内部通信。飞利浦半导体与1982年发明此协议,目标是使用更少的引脚通信。它只使用2条线通信。因此…

视频汇聚平台EasyCVR服务器使用WiFi网卡时,为何无法向级联平台发送注册?

在视频监控平台运维中,级联注册是实现上下级平台视频资源同步的关键。近期,我们协助处理了一起典型的EasyCVR级联故障:用户反馈其下级平台在重启后,始终无法成功注册到上级平台,且上级平台显示下级“不在线”,本…

requests-html在风险管理中的应用:风险数据采集与评估报告 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

ai-answer

数据库设计的三大范式(Three Normal Forms, 3NF) 是关系型数据库设计中用于规范数据表结构、减少数据冗余、提高数据一致性的重要原则。它们依次为:一、第一范式(1NF,First Normal Form) 定义: 确保每张表的每个…

2025 年 11 月纯化水设备厂家推荐排行榜,生物制药纯化水设备,医疗器械纯化水设备,食品纯化水设备,化妆品纯化水设备,制药纯化水设备公司推荐

2025年11月纯化水设备厂家推荐排行榜:专业选购指南与权威品牌解析 在当今严格的产业标准与品质要求下,纯化水设备已成为生物制药、医疗器械、食品加工、化妆品生产等众多行业不可或缺的基础设施。随着技术迭代与市场…

火山引擎多模态数据湖,破解智能驾驶数据处理瓶颈

在近日举办的2025第八届智能辅助驾驶大会上,火山引擎数据产品解决方案专家分享了由多模态数据湖解决方案构成的数据基座,致力于解决智能网联汽车行业面临的海量多模态数据处理难题。该方案通过存储与计算架构的深度优…

The 2025 ICPC Asia Shenyang Regional Contest

Preface 上周的 ICPC 沈阳,只能说每年赛站博弈都大失败,去年的南京和今年的沈阳看来强度是真低啊 VP 的时候因为有场外因素所以没被现场的榜带歪,很早写过了 AG 两个本质铜牌题后发现在现场就稳 Au 了 最后 DF 双开…

2025年交通安全国际学术会议(ICTS 2025)

SAE出版 (ISSN: 0148-7191) | EI稳定检索 2025年交通安全国际学术会议(ICTS 2025) 2025 International Conference on Traffic Safety 【本会作为第五届物流系统与交通运输国际学术会议(LSTT 2025)分会开展】 在这…

2025一对一教育机构口碑排名:高性价比靠谱名单 + 权威测评排行榜

在当今教育生态中,“不能输在起跑线” 的焦虑像滚雪球般越滚越大。家长们为了让孩子在激烈的升学竞争中脱颖而出,不惜花费重金寻找一对一辅导。然而,课外补习市场乱象丛生,各种打着 “名师授课”“个性化定制” 旗…

11.19题解

A. 植树 很明显的二分答案,二分出来,就是一个线段覆盖问题,贪心的想,假如我有一个点没被左边的树覆盖到,那么我期望右边覆盖到他的那棵树尽可能靠后,然后做一下就行了。 B.树树修剪 考虑一个 dp,你一个点的答案…

11.18题解

climb 首先我们有一个状态时 \(O(nV)\) 的 DP,即考虑到第 i 个点,当前高度是 j 的最小代价。 这个状态太大了,我们考虑哪些状态时冗余的。 考虑我一个点经过调整,如果前一个点确定是 t,那么当前这个点可能且只可能…

视频汇聚平台EasyCVR添加设备提示成功,但平台不展示设备的原因排查

EasyCVR视频融合云服务平台支持多协议设备接入、视频汇聚与分发等核心能力,在安防监控、智慧园区等场景中广泛应用。近期我们接到用户反馈,在EasyCVR平台执行设备添加操作后,设备列表始终无新设备显示,这一问题直接…