我正在查询一个有几百万行的表。当我使用带有=的子选择时
select *
from "parcels"
where "parcel_id" = (select "parcel_id"
from "parcels_properties"
where "property_id" = '178528')
该索引将被使用并在 2 秒内返回。
这一点,显然当子查询有多个结果时,我需要使用WHERE IN
. 然后它不会使用索引并给我 10+ 秒。
select *
from "parcels"
where "parcel_id" in (select "parcel_id"
from "parcels_properties"
where "property_id" = '178528')
解释:
"Hash Join (cost=82047.73..357097.98 rows=2019856 width=170)"
" Hash Cond: ((parcels.parcel_id)::text = (parcels_properties.parcel_id)::text)"
" -> Seq Scan on parcels (cost=0.00..241975.11 rows=4039711 width=170)"
" -> Hash (cost=82045.23..82045.23 rows=200 width=38)"
" -> HashAggregate (cost=82043.23..82045.23 rows=200 width=38)"
" Group Key: (parcels_properties.parcel_id)::text"
" -> Gather (cost=1000.00..81970.73 rows=28999 width=38)"
" Workers Planned: 2"
" -> Parallel Seq Scan on parcels_properties (cost=0.00..78070.83 rows=12083 width=38)"
" Filter: ((property_id)::text = '178528'::text)"
在本说明的第 3 行,使用了 a Seq Scan
on parcels
table,而不是parcel_id index
?
还有一件事,这是在 AWS RDS 上。
如果我使用几乎相同的设置在本地数据库上运行相同的 SQL(只有 RDS 是 v14,本地是 v12),它会使用索引并立即返回。
在 parcels 表上创建索引:
- parcel_id
在 parcels_properties 表上创建索引:
- parcel_id
- property_id
那么有人可以帮我解决这个问题吗?
谢谢你。
更新
这样做将对 Parcels 表进行排序强制索引扫描
SET enable_seqscan = OFF;
SELECT *
FROM parcels p
WHERE EXISTS (
SELECT 1
FROM parcels_properties pp
WHERE pp.parcel_id = p.parcel_id AND property_id = '178528'
);