Postgresql 9.x:优化`xpath_exists`(XMLEXISTS)查询的索引

时间:2013-04-18 08:25:51

标签: postgresql postgresql-9.1 postgresql-9.2

我们有表格

的查询
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

plan on explain.depesz.com

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)

plan on explain.depesz.com

1 个答案:

答案 0 :(得分:4)

计划员成本参数

  

第一个计划的成本(seqscan off)略高,但处理时间更快

这告诉我你的random_page_costseq_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倾向于能够使用索引来获取所需的值,而无需进行昂贵的表扫描或索引扫描和排序。

提示

BTW,对于未来的问题,PostgreSQL wiki在performance category中提供了一些很好的信息,并提供了Slow query questions的指南。