我们有表格
的查询select sum(acol)
where xpath_exists('/Root/KeyValue[Key="val"]/Value//text()', xmlcol)
可以构建什么索引来加速where子句?
使用
创建的btree索引create index idx_01 using btree(xpath_exists('/Root/KeyValue[Key="val"]/Value//text()', xmlcol))
似乎根本没有使用。
修改
将enable_seqscan
设置为off
,使用xpath_exists
的查询要快得多(一个数量级),并使用相应的索引(使用{{1}构建的btree索引)清晰显示})。
任何线索为什么PostgreSQL不会使用索引并尝试更慢的顺序扫描?
由于我不想全局禁用顺序扫描,我回到原点,我很高兴欢迎建议。
编辑2 - 解释计划
见下文 - 第一个计划的成本(seqscan off)略高,但处理时间很多更快
xpath_exists
b2box=# set enable_seqscan=off;
SET
b2box=# explain analyze
Select count(*)
from B2HEAD.item
where cluster = 'B2BOX' and ( ( xpath_exists('/MessageInfo[FinalRecipient="ABigBank"]//text()', content) ) ) offset 0 limit 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=22766.63..22766.64 rows=1 width=0) (actual time=606.042..606.042 rows=1 loops=1)
-> Aggregate (cost=22766.63..22766.64 rows=1 width=0) (actual time=606.039..606.039 rows=1 loops=1)
-> Bitmap Heap Scan on item (cost=1058.65..22701.38 rows=26102 width=0) (actual time=3.290..603.823 rows=4085 loops=1)
Filter: (xpath_exists('/MessageInfo[FinalRecipient="ABigBank"]//text()'::text, content, '{}'::text[]) AND ((cluster)::text = 'B2BOX'::text))
-> Bitmap Index Scan on item_counter_01 (cost=0.00..1052.13 rows=56515 width=0) (actual time=2.283..2.283 rows=4085 loops=1)
Index Cond: (xpath_exists('/MessageInfo[FinalRecipient="ABigBank"]//text()'::text, content, '{}'::text[]) = true)
Total runtime: 606.136 ms
(7 rows)
答案 0 :(得分:4)
第一个计划的成本(seqscan off)略高,但处理时间更快
这告诉我你的random_page_cost
和seq_page_cost
可能不对。您可能会使用快速随机I / O进行存储 - 因为大多数数据库都缓存在RAM中,或者因为您使用的是SSD,具有缓存的SAN或其他存储,其中随机I / O本身就很快。
尝试:
SET random_page_cost = 1;
SET seq_page_cost = 1.1;
大大降低成本参数差异然后重新运行。如果这样做,请考虑在postgresql.conf.
中更改这些参数。
您的行数估计是合理的,因此它看起来不像计划程序误估计问题或表统计信息不良的问题。
您的查询也不正确。没有OFFSET 0 LIMIT 1
的{{1}}会产生不可预测的结果,除非您保证只有一个匹配,在这种情况下,ORDER BY
条款是不必要的,可以完全删除。
在可能的情况下,您通常会更好地处理OFFSET ... LIMIT ...
或SELECT max(...)
等问题。 PostgreSQL倾向于能够使用索引来获取所需的值,而无需进行昂贵的表扫描或索引扫描和排序。