所以,我在postgresql数据库中有两个表,一个名为foo
,结构如下:
Column | Type
-------------
id | integer
raw | json
另一个名为bar
,看起来像这样:
Column | Type
-------------
id | integer
action | character varying
foo
的表达式索引如下所示:"foo_expr_idx" btree ((raw ->> 'action'::text))
此索引有效。尽管foo
有数百万行,但我可以运行如下查询:
SELECT * from foo WHERE raw->>'action' = 'open'
它使用索引而不执行顺序扫描。我使用EXPLAIN ANALYZE
验证了这一点。
但是当我在连接中使用该表达式时,它不使用索引。所以加入如:
SELECT * from bar LEFT OUTER JOIN foo ON (bar.action = foo.raw->>'action');
非常缓慢。当我检查它在做什么时,肯定会进行顺序扫描。如何让postgresql在这样的连接中使用表达式索引?
解释的输出如下:
Merge Left Join (cost=1101140.74..1207570.52 rows=5560478 width=175) (actual time=815671.230..873493.479 rows=16673 loops=1)
Output: bar.id, bar.action, foo.id, foo.raw,
Merge Cond: ((bar.action)::text = ((foo.raw ->> 'action'::text)))
-> Sort (cost=1719.29..1745.81 rows=10607 width=131) (actual time=47.439..60.859 rows=10628 loops=1)
Output: bar.id, bar.action
Sort Key: bar.action
Sort Method: external merge Disk: 1024kB
-> Seq Scan on public.bar (cost=0.00..282.07 rows=10607 width=131) (actual time=0.008..10.186 rows=10628 loops=1)
Output: bar.id, bar.action
-> Materialize (cost=1099421.45..1117505.18 rows=3616747 width=44) (actual time=815623.382..864899.131 rows=3614363 loops=1)
Output: foo.id, foo.raw, ((foo.raw ->> 'action'::text))
-> Sort (cost=1099421.45..1108463.31 rows=3616747 width=44) (actual time=815623.356..851265.324 rows=3608287 loops=1)
Output: foo.id, foo.raw, ((foo.raw ->> 'action'::text))
Sort Key: ((foo.raw ->> 'action'::text))
Sort Method: external merge Disk: 2611952kB
-> Seq Scan on public.foo (cost=0.00..371670.47 rows=3616747 width=44) (actual time=0.052..121762.195 rows=3612522 loops=1)
Output: foo.id, foo.raw, (foo.raw ->> 'action'::text)
Total runtime: 874110.670 ms
(18 rows)
答案 0 :(得分:0)
问题似乎是Postgresql对那些不合适的数据做了一些假设。简单的解决方案是分析表格......
运行后
analyze foo;
我的查询运行时间从14分钟下降到259毫秒。