2

最近我對Clojure很熟悉,我對懶惰序列評估的想法感到好笑,它只在必要時計算值。LIMIT優化查詢

我使用PostgreSQL數據庫工作了很多,並且在使用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行。這種行爲與懶惰的想法相反,因爲數據庫過程數據不需要得到最終答案。但在另一方面查詢

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的操作支持這樣的限制懶惰?

+2

注:'LIMIT'沒有'ORDER BY'很少或沒有意義。 – wildplasser 2014-12-27 19:23:50

+1

有關查詢計劃或性能的問題,請總是***包括您的Postgres版本和您的案例的確切表格定義。閱讀['[postgresql-performance]'](http://stackoverflow.com/tags/postgresql-performance/info)的標籤信息。索引和約束特別相關。 – 2014-12-28 00:13:47

+0

@wildplasser:只要一個*任意*選擇是好的,'LIMIT'可以在沒有ORDER BY的情況下使用。儘管如此,許多新手並沒有意識到細節,所以我們在SO上看到大多數不正確的查詢就像這個問題。 – 2014-12-28 01:25:57

回答

1

對於初學者,您的查詢是不等於除非id在兩個表中都被定義爲唯一。 INTERSECT處理與INNEROUTER JOIN不同的重複項。缺失的關鍵字ALL使差異更大。 Per documentation:

除非指定 ALL選項的INTERSECT結果不包含任何重複的行。用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.3頁的快速測試中,我只能從INTERSECT中獲得連續掃描,其中連接使用更快的索引掃描。我不知道在第9.4節中有關於INTERSECT的任何消息。

有可能改善,尤其是在涉及獨特索引的情況下。我想沒有人會在意這件事,因爲INTERSECT不像其他操作那樣受歡迎。

我知道的非常漂亮的用例與LIMIT組合UNION ALL從 「懶惰評估」 中獲益,但: