LIMIT优化查询

时间:2014-12-27 19:20:46

标签: sql postgresql query-optimization lazy-evaluation postgresql-performance

最近我对Clojure越来越熟悉了,我对懒惰序列评估的想法很感兴趣,它只在必要时计算值。

我使用PostgreSQL DB工作很多,并且在使用LIMIT子句时遇到了不同的查询性能。例如查询

SELECT * FROM(
    SELECT id FROM foo1
    INTERSECT
    SELECT id FROM foo2) AS subquery
LIMIT 50 

将具有与

相同的执行时间
SELECT id FROM foo1
INTERSECT
SELECT id FROM foo2.

这表明Postgres首先评估整个结果,然后获得前50行。这种行为与懒惰的想法相反,因为DB处理数据不需要得到最终答案。但另一方面查询

SELECT * FROM foo1 INNER JOIN foo2 ON foo1.id=foo2.id LIMIT 50

表现得更好
SELECT * FROM foo1 INNER JOIN foo2 ON foo1.id=foo2.id.

有人知道哪些Postgres操作支持LIMIT懒惰吗?

1 个答案:

答案 0 :(得分:1)

对于初学者,您的查询不等同,除非id在两个表中都是唯一的。 INTERSECT处理重复项的方式与INNEROUTER JOIN不同。缺少关键字 ALL 会使差异更大。 Per documentation:

  

INTERSECT的结果不包含任何重复的行,除非   指定了ALL选项。使用ALL时,行中有m个重复的行   左表格和右侧表格中的n重复项将显示为min(m,n)   结果集中的时间。

另一方面,

联接生成一个笛卡尔积,即m*n行,用于匹配重复项。因此查询计划不能使用相同的代码路径。

要获得相差较少的结果(但仍然不等同除了唯一的id),请改用:

SELECT id FROM foo1
INTERSECT ALL  -- don't fold dupes
SELECT id FROM foo2
LIMIT 50;

SELECT * FROM foo1 JOIN foo2 USING (id) LIMIT 50; -- return single id column

这是a fiddle to play with(第9.3.1页)。 sqlfiddle.com上的版本现在已经过时了。而是自己测试最新版本。

很多更多的时间和智能进入连接的优化,这些连接更常用于几个数量级。我几乎没有使用INTERSECT,因为它经常产生较差的查询计划。在对第9页的快速测试中,我只能从INTERSECT中获得连续扫描,其中连接使用更快的索引扫描。我不知道第9.4页中有关INTERSECT的任何新闻。

有可能改进,特别是在涉及独特索引的情况下。我想没有人关心它,因为INTERSECT不如其他操作那么受欢迎。

我知道UNION ALLLIMIT结合使用的非常好的用例,可以从“懒惰评估”中受益,但是: