Postgres ltree查询中的Cstring

时间:2015-05-18 10:35:02

标签: postgresql

我们使用ltree处理一些分层数据来使用postgres中的sql。

然而,当我们使用强制转换语法时,查询将会非常缓慢,并且查询计划显示它实际上是先强制转换为cstring然后lquery

explain analyse SELECT DISTINCT
                subltree(metric, 0, 6) metric,
                FROM demo
                WHERE
                    metric ~ ('s.a.b' || '.*')::lquery;

查询计划:

Unique  (cost=144235.79..144273.81 rows=3802 width=100) (actual time=11822.107..11822.107 rows=1 loops=1)
   ->  Sort  (cost=144235.79..144245.29 rows=3802 width=100) (actual time=11822.107..11822.107 rows=1 loops=1)
         Sort Key: (subltree(metric, 0, 6))
         Sort Method: quicksort  Memory: 25kB
         ->  Seq Scan on demo  (cost=0.00..144009.71 rows=3802 width=100) (actual time=1940.149..11822.093 rows=1 loops=1)
               Filter: (metric ~ ('s.a.b.*'::cstring)::lquery)
               Rows Removed by Filter: 3714258
 Total runtime: 11822.139 ms

然而,当我们使用下面的sql时,一切似乎都很好:

explain analyse SELECT DISTINCT
                subltree(metric, 0, 6) metric,
                FROM demo
                WHERE
                    metric_name ~ (select ('s.a.b' || '.*')::lquery);

查询计划:

Unique  (cost=13294.81..13313.85 rows=3809 width=76) (actual time=0.122..0.126 rows=6 loops=1)
InitPlan 1 (returns $0)
 ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.007..0.007 rows=1 loops=1)
->  Sort  (cost=13294.79..13304.32 rows=3809 width=76) (actual time=0.121..0.122 rows=6 loops=1)
     Sort Key: metric
     Sort Method: quicksort  Memory: 26kB
     ->  Bitmap Heap Scan on demo  (cost=589.93..13068.25 rows=3809 width=76) (actual time=0.103..0.109 rows=6 loops=1)
           Recheck Cond: (metric ~ $0)
           ->  Bitmap Index Scan on metric_gist_idx  (cost=0.00..588.98 rows=3809 width=0) (actual time=0.097..0.097 rows=6 loops=1)
                 Index Cond: (metric ~ $0)
Total runtime: 0.153 ms

1 个答案:

答案 0 :(得分:3)

基本上,这是ltree扩展程序中的错误。

问题的核心是I / O例程 - 负责在lquery和字符串之间进行转换的函数 - 被错误地标记为VOLATILE。因为这些函数可能有副作用,Postgres不能通过使用索引来优化任何比较;为了保证可预测的行为,规划者需要确保在每一行都调用强制转换。

这是一个与子查询不同的故事。在可能的情况下,Postgres只会评估子查询一次,无论波动性如何。例如,比较

的输出
SELECT random()
FROM generate_series(1,10);

SELECT (SELECT random())
FROM generate_series(1,10);

无论如何,在所有受支持的Postgres版本中,该错误都有already been fixed,但该修补程序不会影响现有数据库。转储/恢复应更新扩展。或者,这应该具有相同的效果:

ALTER FUNCTION ltree_in(cstring) IMMUTABLE;
ALTER FUNCTION ltree_out(ltree) IMMUTABLE;
ALTER FUNCTION lquery_in(cstring) IMMUTABLE;
ALTER FUNCTION lquery_out(lquery) IMMUTABLE;
ALTER FUNCTION ltxtq_in(cstring) IMMUTABLE;
ALTER FUNCTION ltxtq_out(ltxtquery) IMMUTABLE;
ALTER FUNCTION ltree_gist_in(cstring) IMMUTABLE;
ALTER FUNCTION ltree_gist_out(ltree_gist) IMMUTABLE;
相关问题