'Why wont postgresql use index for the query?
I have this small query
select t.* from table1 t
left join table2 t2 on t2.related_uuid = t.uuid and t2.inventoried is true
where t2.org like 'org%' or t.org like 'org%'
Both table1 and table2 have few thousand rows (< 5000). But this query takes ~6 seconds to run. Given that table2.inventoried is true is common in many queries, i thought maybe i should add a partial index over inventoried column with condition inventoried is true could improve performance. Table2 is 90% inventoried is false and 10% inventoried is true. But when looking at explain it does not use the index.
Additionally Table2 contains a column type which can have values: table1, table3, table4. So i could also go with index over it and add an additional condition to the join where t2.type = 'table1'. But this also goes unused.
Index creation queries
create index idx on table2(inventoried) where inventoried is true
create index idx2 on table2(type) where type = 'table1'
I think im doing something wrong, but i just cant quite put my finger on it.
EDIT: Execution plan without indexes
"Hash Right Join (cost=227.83..361.03 rows=3024 width=331) (actual time=0.912..2.242 rows=982 loops=1)"
" Hash Cond: (t2.related_uuid = t.uuid)"
" Filter: ((t2.org ~ 'St%'::text) OR (t.org ~ 'St%'::text))"
" Rows Removed by Filter: 2168"
" Buffers: shared hit=274"
" -> Seq Scan on table2 t2 (cost=0.00..129.85 rows=1276 width=58) (actual time=0.007..0.300 rows=1265 loops=1)"
" Filter: (inventoried IS TRUE)"
" Rows Removed by Filter: 11"
" Buffers: shared hit=117"
" -> Hash (cost=188.48..188.48 rows=3148 width=331) (actual time=0.893..0.893 rows=3150 loops=1)"
" Buckets: 4096 Batches: 1 Memory Usage: 1104kB"
" Buffers: shared hit=157"
" -> Seq Scan on table1 t (cost=0.00..188.48 rows=3148 width=331) (actual time=0.004..0.423 rows=3150 loops=1)"
" Buffers: shared hit=157"
"Planning Time: 0.153 ms"
"Execution Time: 2.315 ms"
Solution 1:[1]
It is going to be hard to get a usable index for an OR which draws from two different tables. You could instead write it as a union:
select t.* from table1 t where t.org like 'org%'
union [all?]
select t.* from table1 t join table2 t2 on t2.related_uuid = t.uuid where t2.inventoried is true and t2.org like 'org%'
But, will this deal with duplicate rows in a manner you find acceptable? Only you can answer that.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | jjanes |
