You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL10查询触发全表扫描未走索引问题咨询

问题原因
  • PostgreSQL 10版本的CTE是优化屏障:该版本对CTE的处理逻辑是单独物化CTE的结果,不会把CTE的关联条件、过滤逻辑下推到外层表查询,因此优化器无法感知到你仅需要匹配少量tx_id,反而默认按照全量关联的场景选择执行计划。
  • 执行计划选择了Merge Join策略:Merge Join要求两个关联数据集都按照关联键tx_id排序,小的CTE结果集排序成本极低,但1.5亿行的大表erc20_transf排序需要先全表扫描获取所有数据,因此出现了全表扫的情况。
  • 统计信息微小偏差:优化器估算CTE返回5622行,但实际仅返回340行,进一步放大了执行计划选择的错误,但核心诱因还是PG10的CTE特性限制。
解决方案

方案1:把CTE替换为普通子查询(最优)

PG10对普通子查询会做条件下推优化,优化器可以识别到可以用tx_id索引匹配少量值,直接走你基准测试验证过的索引扫描逻辑,两种写法都可以:

写法1:IN子查询

select 
  e20t.time_stamp,e20t.amount 
from erc20_transf e20t 
where e20t.tx_id in (
  select tx_id 
  from pol_tok_id_ops 
  where condition_id='e3b423dfad8c22ff75c9899c4e8176f628cf4ad4caa00481764d320e7415f7a9'
);

写法2:JOIN子查询

select 
  e20t.time_stamp,e20t.amount 
from erc20_transf e20t 
join (
  select tx_id 
  from pol_tok_id_ops 
  where condition_id='e3b423dfad8c22ff75c9899c4e8176f628cf4ad4caa00481764d320e7415f7a9'
) txs on txs.tx_id=e20t.tx_id;

方案2:保留CTE但转成数组匹配

如果一定要保留CTE写法,可以手动把tx_id聚合为数组,走基准测试验证过的ANY索引逻辑:

with txs as (
  select array_agg(tx_id) as tx_ids
  from pol_tok_id_ops 
  where condition_id='e3b423dfad8c22ff75c9899c4e8176f628cf4ad4caa00481764d320e7415f7a9'
)
select 
  e20t.time_stamp,e20t.amount 
from erc20_transf e20t, txs
where e20t.tx_id = any(txs.tx_ids);

方案3:会话级别禁用低效关联策略

临时关闭Merge Join和Hash Join,强制优化器走嵌套循环关联(小结果集驱动大表走索引):

-- 会话级别临时生效,断开连接后自动恢复
set enable_mergejoin = off;
set enable_hashjoin = off;
-- 再执行你原来的CTE查询即可

内容的提问来源于stack exchange,提问作者Nulik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:54:03