Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 涉及视图和函数的查询不能使用索引_Postgresql_Plpgsql_Database Performance - Fatal编程技术网

Postgresql 涉及视图和函数的查询不能使用索引

Postgresql 涉及视图和函数的查询不能使用索引,postgresql,plpgsql,database-performance,Postgresql,Plpgsql,Database Performance,为了便于阅读,我简化了以下postgresql查询: select * from a_view where a in (select * from a_function(a_input)) and b in (select * from b_function(b_input)); 此查询执行速度非常慢 如果我独立运行这两个子查询,它们会非常快。如果我运行查询并写出子查询的输出,即: select * from a_view where a in (394990, 393762, 3

为了便于阅读,我简化了以下postgresql查询:

select *
from a_view
where a in (select * from a_function(a_input))
      and b in (select * from b_function(b_input));
此查询执行速度非常慢

如果我独立运行这两个子查询,它们会非常快。如果我运行查询并写出子查询的输出,即:

select *
from a_view
where a in (394990, 393762, 393748, 1)
      and b in (331142, 330946, 331228, 331325);
这也相当快。我在上面的原始表单中运行解释分析和实现,查询不能使用索引,而是使用顺序扫描。更详细地说,视图a_视图涉及一个1000多万行的大表,它在a、b和b上都有索引


有没有办法帮助query利用索引?

可能有两个问题:

默认情况下,任何SRF函数都会在1000上包含ROWS子句—规划器也希望如此。你的例子是错误的。尝试将此属性设置为更合适的值,例如,10-太小也可能不好:

postgres=# explain select * from xx();
┌───────────────────────────────────────────────────────────┐
│                        QUERY PLAN                         │
╞═══════════════════════════════════════════════════════════╡
│ Function Scan on xx  (cost=0.25..10.25 rows=1000 width=4) │
└───────────────────────────────────────────────────────────┘
(1 row)
PLpgSQL函数是规划器的黑盒。与使用函数相比,如果您只使用常量列表,那么planner有更多关于谓词的信息。在这种情况下,规划者必须使用一些默认规则,这些规则对于您的案例来说可能太过时了

postgres=# explain select * from xx where a in (10,20);
┌────────────────────────────────────────────────────┐
│                     QUERY PLAN                     │
╞════════════════════════════════════════════════════╡
│ Seq Scan on xx  (cost=0.00..170.00 rows=2 width=4) │
│   Filter: (a = ANY ('{10,20}'::integer[]))         │
└────────────────────────────────────────────────────┘
(2 rows)

postgres=# explain select * from xx where a in (select * from xx());
┌──────────────────────────────────────────────────────────────────────────────────┐
│                                    QUERY PLAN                                    │
╞══════════════════════════════════════════════════════════════════════════════════╡
│ Hash Join  (cost=17.25..201.85 rows=5000 width=4)                                │
│   Hash Cond: (xx.a = xx_1.xx)                                                    │
│   ->  Seq Scan on xx  (cost=0.00..145.00 rows=10000 width=4)                     │
│   ->  Hash  (cost=14.75..14.75 rows=200 width=4)                                 │
│         ->  HashAggregate  (cost=12.75..14.75 rows=200 width=4)                  │
│               Group Key: xx_1.xx                                                 │
│               ->  Function Scan on xx xx_1  (cost=0.25..10.25 rows=1000 width=4) │
└──────────────────────────────────────────────────────────────────────────────────┘
(7 rows)
我有两个可能相同的查询,它们的计划非常不同,性能可能也非常不同

解决方案可以是什么:

不要这样做-在SQL查询中的关键位置(主要是WHERE子句)使用plpgsql可能会产生非常负面的影响

您可以重写函数以返回int[]而不是setint。在这种情况下,规划器将使用不同的规则,性能会更好

postgres=# explain select * from xx where a = any( xx2());
┌──────────────────────────────────────────────────────┐
│                      QUERY PLAN                      │
╞══════════════════════════════════════════════════════╡
│ Seq Scan on xx  (cost=0.00..2770.00 rows=11 width=4) │
│   Filter: (a = ANY (xx2()))                          │
└──────────────────────────────────────────────────────┘
(2 rows)
如果a_函数和b_函数的结果不依赖于内容a和b,那么可以在查询之前通过在这些函数上设置不可变的标志对它们进行评估。然后在计划时间内对函数进行评估,并将结果用作常数,planner将获得更多信息。注意:如果前提条件为false,则结果可能是错误的。小心点

-- xx2 is IMMUTABLE now
postgres=# explain select * from xx where a = any( xx2());
┌───────────────────────────────────────────────────────┐
│                      QUERY PLAN                       │
╞═══════════════════════════════════════════════════════╡
│ Seq Scan on xx  (cost=0.00..182.50 rows=3 width=4)    │
│   Filter: (a = ANY ('{30314,3783,70448}'::integer[])) │
└───────────────────────────────────────────────────────┘
(2 rows)

您可以尝试将select*from a_Function_input放入CTE,看看是否有任何变化。这里是CTE版本:从a_Function_input中选择a_temp,从b_Function中选择b_temp,从b_input中选择b_temp,从a_temp中选择a,从b_temp中选择b@没有名字的马:将使用连接而不是in。。帮助?使用连接也没有帮助。我尝试编写查询而不是使用视图,这也没有帮助:您建议的解决方案3实际上就是我想要的。我先试了一下,但令我失望的是,这并没有起到任何作用。我也确实放弃了ALL以删除所有缓存的查询计划。@MMatt:我不确定它是否适用于SELECT中的子句'=中。结果必须是一个数组,而不是一个集合。@MMatt:good old trick:它应该在列表中的某个地方,也在你的第1期中。你说尝试将这个属性设置为更合适的值,我该怎么做?@MMatt:It is typo-应该在“从外汇中选择”中。尽管它在视觉上相似,但实现与=ANYfx有很大不同。