我有查询(简体版):
WITH temp AS (SELECT id, foo(id) AS foo FROM test)
SELECT id FROM temp WHERE foo = 4;
foo(id)
是返回0、2或4(仅这些值)的函数
使用... WHERE foo = 4
进行上述查询需要花费几分钟,但是令人惊讶的是,当我更改为... WHERE foo != 0 AND foo != 2
时,查询性能为毫秒。
就算我... WHERE foo > 2
也一样-速度也很快。
我检查了执行计划,但没有发现任何差异。
对此感到非常惊讶……有人可以向我解释原因吗?
答案 0 :(得分:1)
假设函数foo()
不能被内联,Postgres不知道它可能返回什么,因此必须假定任何数字都是相同的。
谓词foo = 4
告诉Postgres期望无行旁边将符合条件。
谓词foo != 0 AND foo != 2
(OTOH)告诉Postgres期望几乎所有行合格。使用foo > 2
,它仍然占所有行的一半。
这通常会导致不同的查询计划,第一个查询计划似乎表现不佳,而另一个查询计划似乎表现良好。
由于缺少信息而隐藏了详细信息。但这就是重点。
如果函数为IMMUTABLE
,则可以在foo(foo(id))
上创建表达式索引。假设3个可能的值均匀分布,那么该索引本身可能就没有用。 (也许对多列索引foo(foo(id), id)
进行的仅索引扫描会有所帮助,如果函数很昂贵并声明为这样的话。)但是这使Postgres收集了额外的统计信息,这些信息会告诉查询计划者对功能有什么期望。相关: