Postgresql не использует индекс WHERE IN, но работает с WHERE = [закрыто]
Я запрашиваю таблицу с несколькими миллионами строк. Когда я использую подвыбор с =
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 этого объяснения
Seq Scan
на
parcels
используется таблица вместо
parcel_id index
?
Еще одна вещь, это на AWS RDS.
Если я запускаю тот же SQL в своей локальной базе данных с почти такой же настройкой (только RDS — v14, локальная — v12), он использует индекс и мгновенно возвращается.
Создан индекс в таблице посылки:
- id_посылки
Создан индекс для таблицы packages_properties:
- 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'
);
2 ответа
Вы никогда не говорили нам, какие индексы вы определили, но в любом случае я бы выразил ваш запрос, используя существующую логику:
SELECT *
FROM parcels p
WHERE EXISTS (
SELECT 1
FROM parcels_properties pp
WHERE pp.parcel_id = p.parcel_id AND property_id = '12345'
);
Этот запрос должен выиграть от следующего индекса на
parcels_properties
:
CREATE INDEX idx_pp ON parcel_properties (property_id, parcel_id);
Для любого может быть такая же проблема в будущем. Попробуйте ВАКУУМИРОВАТЬ базу данных.
я сделал полный
VACUUM
базы данных, и это сработало.
vacuumdb --echo --full --verbose --analyze -h yourdbhost -p 5432 -U your username -d yourdbname