【问题标题】:Bad performance on EXISTS-clauses in functions函数中 EXISTS 子句的性能不佳
【发布时间】:2014-11-03 21:54:12
【问题描述】:

我想在 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 子句。实际上,与以下查询相比,该查询非常慢(内联 EXISTS 子句而没有 SELECT 子句):

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$

但现在我在函数的一张表上只有一个子查询,这对我来说没有用。有关如何正确执行此操作以免遇到性能问题的任何建议?

谢谢!

【问题讨论】:

  • EXISTS 往往会导致相关子查询,这对 DBMS 来说更难优化;使用 IN/NOT IN 往往更有效。
  • @okaram:完全错误。请注意,在这种情况下没有相关的子查询,因为没有主查询。
  • @wildplasser,函数中的查询是不相关的,但上面那个是(但我在发表评论时不明白问题是函数:)

标签: function postgresql plpgsql inline-code


【解决方案1】:

好的,我想我明白你的问题是什么了;函数调用不可优化,需要在函数外进行查询;像

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

【讨论】:

  • 这里没有理由偏爱NOT IN(...); NOT EXISTS(...) 也可以,甚至更好。 OQ中的性能问题在于函数调用,优化器无法分解。
  • @wildplasser 我现在明白问题在于函数调用;但是,通常 in/not in 查询更容易优化,对吧? EXISTS 倾向于做相关子查询(需要在查询中引用外部行),这对优化器来说更难
  • 在过去几年我在 Postgres 中进行的几乎所有无数次测试中,NOT EXISTS 都比NOT IN 快。此外,NOT IN 对 NULL 值表现出棘手的行为。 More here.。即将到来的 pg 9.4 可能会有变化。不说有,也不期待。只是还没有测试。
猜你喜欢
  • 2013-03-26
  • 1970-01-01
  • 2021-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 2013-02-10
  • 2011-10-28
相关资源
最近更新 更多