2015-10-16 41 views
5

的PostgreSQL 9.4 表如下所示創建。爲了最有效,我傾向於在下面的查詢使用Index Only Scan爲什麼不能在索引創建的索引上使用僅索引掃描?</p> <pre><code>CREATE TABLE foo ( id integer, date date, value numeric(14,3) ); </code></pre> <p>我使用的<code>ROW_NUMBER()</code>窗口功能和<code>COALESCE</code>優化查詢:

SELECT id, c_val 
FROM (
    SELECT id, COALESCE(value, 0) c_val, ROW_NUMBER() OVER(PARTITION BY id ORDER BY date DESC NULLS LAST) rn 
    FROM foo) sbt 
WHERE sbt.rn = 1; 

所以,如果我創建指標如下:

CREATE INDEX ON foo (id, date DESC NULLS LAST, value); 

規劃者選擇使用Index Only Scan,但如果我這樣做它以這種方式:

CREATE INDEX ON foo (id, date DESC NULLS LAST, COALESCE(value, 0)); 

規劃師只會做Index Scan

爲什麼?我試圖避免在執行查詢時評估COALESCE函數的成本。爲什麼它不適用於Index Only Scan

+2

coalesce()的「成本」幾乎爲零,不用擔心。 –

回答

1

我認爲你錯誤地認爲你的SELECT中的COALESCE(value, 0)就索引使用而言很重要。說實話,只有在之後纔會返回視圖轉換。

就索引使用而言,重要的是您的WINDOW FUNCTION。首先你劃分id,然後你通過date DESC NULLS LAST爲每個分區排序值。這兩件事情決定了像CREATE INDEX ON foo (id, date DESC NULLS LAST, ...)這樣的索引對你放在下一個位置的任何東西都很有用。 請注意,如果您在創建索引時更改了iddate的順序,PostgreSQL根本不會使用該索引。

現在,您必須知道INDEX ONLY SCAN只有在索引本身存儲查詢所請求的整個未觸動的行值時才能使用。 PostgreSQL manual後:

如果索引存儲的原始索引的數據值(而不是他們的一些有損表示),它是支持僅索引掃描,其中指數收益率的實際數據非常有用...

在你的情況你seccond索引存儲行的一些有損表示因爲最後一列的值由函數和查詢要求idvaluedate轉化。 PostgreSQL並不那麼聰明,它只是NULLs0的替代。對他來說這不是原來的價值。所以我們需要訪問表來獲取原始行值(最後使用普通的)。之後,將值格式化爲輸出併發生COALESCE(values, 0)

編輯:

我想解釋足夠你至於你的內部發生的問題有關。要談論COALECE()評估成本,我同意a_horse_with_no_name,你可能不應該擔心這一點。

+0

啊,我不知道提取發生在'COALESCE'的情況下,如果我可以這麼說... –

+0

因爲我準確地回答了你的問題並解釋了一些事情,並且你學到了一些你不知道的東西(如你說的)爲什麼不接受我的回答? –

+0

忘了這麼做... –

相關問題