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
Другие вопросы по тегам