Документация , на которую вы ссылаетесь, гласит: «Планировщик иногда предпочитает использовать простое сканирование индекса, даже если доступны дополнительные индексы, которые также могли бы использоваться».
Iне удалось заставить postgres (8.4) вести себя так, как вы хотите, когда условие where
содержало подзапросы - только с простыми условиями, поэтому это могло быть просто ограничением функции.
Но сутьна самом деле, хотя оптимизатор попытается выбрать самый быстрый путь выполнения, он может не сработать, и в некоторых случаях вам может потребоваться «поощрить» другой путь, как я сделал в «модифицированном» запросе ниже с union
:
create table distritos(id serial primary key, distrito_t text);
insert into distritos(distrito_t) select 'distrito'||generate_series(1, 10000);
create table concelho(id serial primary key, concelho_t text);
insert into concelho(concelho_t) select 'concelho'||generate_series(1, 10000);
create table entidades( eid serial primary key,
distrito integer not null references distritos,
concelho integer not null references concelho );
insert into entidades(distrito, concelho)
select generate_series(1, 10000), generate_series(1, 10000);
оригинал:
explain analyze
select eid from entidades
where concelho in (select id from concelho where concelho_t like '%lisboa%')
or distrito in (select id from distritos where distrito_t like '%lisboa%');
QUERY PLAN
-------------------------------------------------------------------------------------------------------------
Seq Scan on entidades (cost=299.44..494.94 rows=7275 width=4) (actual time=8.978..8.978 rows=0 loops=1)
Filter: ((hashed SubPlan 1) OR (hashed SubPlan 2))
SubPlan 1
-> Seq Scan on concelho (cost=0.00..149.71 rows=2 width=4) (actual time=3.922..3.922 rows=0 loops=1)
Filter: (concelho_t ~~ '%lisboa%'::text)
SubPlan 2
-> Seq Scan on distritos (cost=0.00..149.71 rows=2 width=4) (actual time=3.363..3.363 rows=0 loops=1)
Filter: (distrito_t ~~ '%lisboa%'::text)
изменено:
explain analyze
select eid from entidades
where concelho in (select id from concelho where concelho_t like '%lisboa%')
union
select eid from entidades
where distrito in (select id from distritos where distrito_t like '%lisboa%');
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=648.98..650.92 rows=194 width=4) (actual time=5.409..5.409 rows=0 loops=1)
-> Append (cost=149.74..648.50 rows=194 width=4) (actual time=5.399..5.399 rows=0 loops=1)
-> Hash Semi Join (cost=149.74..323.28 rows=97 width=4) (actual time=2.743..2.743 rows=0 loops=1)
Hash Cond: (stack.entidades.concelho = concelho.id)
-> Seq Scan on entidades (cost=0.00..147.00 rows=9700 width=8) (actual time=0.013..0.013 rows=1 loops=1)
-> Hash (cost=149.71..149.71 rows=2 width=4) (actual time=2.723..2.723 rows=0 loops=1)
-> Seq Scan on concelho (cost=0.00..149.71 rows=2 width=4) (actual time=2.716..2.716 rows=0 loops=1)
Filter: (concelho_t ~~ '%lisboa%'::text)
-> Hash Semi Join (cost=149.74..323.28 rows=97 width=4) (actual time=2.655..2.655 rows=0 loops=1)
Hash Cond: (stack.entidades.distrito = distritos.id)
-> Seq Scan on entidades (cost=0.00..147.00 rows=9700 width=8) (actual time=0.006..0.006 rows=1 loops=1)
-> Hash (cost=149.71..149.71 rows=2 width=4) (actual time=2.642..2.642 rows=0 loops=1)
-> Seq Scan on distritos (cost=0.00..149.71 rows=2 width=4) (actual time=2.642..2.642 rows=0 loops=1)
Filter: (distrito_t ~~ '%lisboa%'::text)