函数中EXISTS子句的性能不佳

时间:2014-11-03 21:54:12

标签: function postgresql plpgsql inline-code

我有以下函数,我想在sql查询中使用它(Postgres 9.3):

SELECT * FROM test_table tt WHERE has_access(tt.id, tt.login)

CREATE OR REPLACE FUNCTION has_access(integer, integer)
RETURNS boolean AS
$BODY$
SELECT
  EXISTS (SELECT true
            FROM test_read_access
          WHERE id = $1 and login = $2 
  )
  AND
  NOT EXISTS (SELECT true
            FROM test_no_read_access
          WHERE id = $1 and login = $2 
  )
$BODY$

只要我只关心功能正确性,这个工作正常。因为查询分析器告诉我,必须为每一行评估函数,因此无法按预期优化EXISTS子句。实际上,与以下查询相比,查询非常慢(在没有SELECT子句的情况下内联EXISTS子句):

SELECT * FROM test_table tt WHERE 
   EXISTS (SELECT true
            FROM test_read_access
          WHERE id = tt.id and login = tt.login 
  )
  AND
  NOT EXISTS (SELECT true
            FROM test_no_read_access
          WHERE id = tt.id and login = tt.login 
  )

函数has_access(id,login)的意图是在函数中对某些访问规则进行分组,然后在不同的查询中使用它。我的意思是,可以做这样的事情来获得良好的表现:

SELECT * FROM test_table tt WHERE EXISTS (select has_access(tt.id, tt.login))

CREATE OR REPLACE FUNCTION has_access(integer, integer)
RETURNS SETOF boolean AS
$BODY$
SELECT true
   FROM test_read_access
WHERE id = $1 and login = $2 
$BODY$

但是现在我在函数中的一个表上只有一个子查询,这在我的情况下没用。有关如何正确执行此操作以避免遇到性能问题的任何建议吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

好的,我想我知道你的问题是什么;函数调用不可优化,因此需要在函数外部进行查询;

之类的东西
SELECT *
  FROM test_table
WHERE (id,login) IN (SELECT id,login FROM test_read_access)
  AND (id,login) NOT IN (SELECT id,login FROM test_no_read_access)

检查http://sqlfiddle.com/#!12/94a02/2