2012-05-30 19 views
1

我正在建立一個博客,我有一個問題。應該有一些粘性帖子。我想要的是首先得到粘性帖子,然後是其餘的。sql查詢首先獲得粘性帖子

一個查詢的工作原理是

select * from 

(
(select *,true as st from blog where "stickyUntil" > current_timestamp) 
UNION all 
(SELECT *,false as st from blog where "stickyUntil" < current_timestamp or "stickyUntil" is null ) 
) q 


order by st desc, "stickyUntil" DESC ,publish DESC OFFEST x LIMIT z 

是workz另一個更簡單的查詢是

select * from blog order by case when "stickyUntil" > current_timestamp then "stickyUntil" end desc nulls last, publish desc; 

但是,這將迫使200.000排在內存中不是很快進行排序..

是有一種方法來優化它?

使用兩個單獨的查詢會更好嗎? 感謝

+0

你先查詢看起來不錯。工會沒有錯。在申請限制之前,你是否想要拉太多行?那麼爲什麼要在UNION的每個子查詢中添加一個「LIMIT z」?這將限制子查詢返回的整個集合最大爲2z條記錄。 – Glenn

+0

雖然這個,但它似乎與分頁問題..然後爲了確定OFFSET在第二個查詢我將不得不調用計數的第一個查詢。如果有5個貼,那麼偏移10應該是5 ..應我這樣做? – GorillaApe

+0

@Paths Typo在第一條評論中應該是「爲什麼不添加限制...」。不知道我是否按照這個問題。第一個查詢的LIMIT z沒有OFFSET,第二個查詢的LIMIT z沒有OFFSET,然後你的包裝查詢保持原樣。 – Glenn

回答

3

我將與CASE語句去避免表的兩個遍:

select *, 
    CASE 
    WHEN "stickyUntil" > current_timestamp THEN true 
    ELSE false 
    END as st 
FROM blog 
ORDER BY st DESC ,publish DESC OFFEST x LIMIT z 

的Postgres支持創建一個計算字段,這將有助於在這裏的INDEX但有一個限制:

在索引定義中使用的必須是「不可改變的」所有的功能和運營商, 也就是說,它們的結果必須僅僅依靠他們的論點,從不在外面任何 注量(例如另一個表格的內容或當前時間)。

所以你不能索引st計算。如果ST的計算並不需要太精確的另一種選擇是將ST字段添加到表:

ALTER TABLE blog 
ADD COLUMN st boolean default true 

INDEXST的定期專欄:

CREATE INDEX sti ON blog(st) 

並定期執行:

UPDATE blog 
SET st = false 
WHERE st = true 
AND "stickyUntil" < current_timestamp 

,但是進行更新的輪詢過程比直接查詢要少得多。這隻有在您的查詢非常緩慢或者有很多博客表讀取時纔有意義。

+0

這不排序應該的方式。如果stickyUntil datetime已經通過發佈應該只有問題...我想知道是否有一種方法來索引訂單... – GorillaApe

+0

(哎呀,只是注意到我的評論重複CASE/NULLS LAST你已經嘗試過了。) –

+0

你是對的。如果在** stickyUntil **通過後發佈順序優先,那麼它將不起作用。我會更新答案來反映這一點。 – pd40

1

我認爲你最好關閉兩個查詢,一個用於粘貼,另一個用於其他。

SQL不保證結果的順序,沒有明確的順序。雖然UNION ALL的結果似乎正確,但不能保證。這在多線程環境中變得更加明顯,您不知道哪個線程會先完成數據讀取並開始返回結果。

最有效的解決方法是將其作爲兩個不同的查詢。

+0

我認爲這就是我要做的......儘管這可能是解決方案。我雖然使用索引,但似乎不可能隨時間戳更改.. – GorillaApe

0
select * 
from blog 
order by 
    coalesce("stickyUntil", '1901-01-01'::date) < current_timestamp, 
    publish DESC 
OFFSET x LIMIT z