2010-02-10 110 views
10

我剛剛重組了我的數據庫,使用PostgreSQL 8.2中的partitioning。現在我遇到查詢性能問題:多分區Postgres表的高效查詢

SELECT * 
FROM my_table 
WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
ORDER BY id DESC 
LIMIT 100; 

表中有4500萬行。在分區之前,這將使用反向索引掃描並在達到極限時立即停止。

分區後(在time_stamp範圍內),Postgres會對主表和相關分區執行完整索引掃描,併合並結果,對它們進行排序,然後應用限制。這需要太長時間。

我可以解決這個問題:

SELECT * FROM (
    SELECT * 
    FROM my_table_part_a 
    WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
    ORDER BY id DESC 
    LIMIT 100) t 
UNION ALL 
SELECT * FROM (
    SELECT * 
    FROM my_table_part_b 
    WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
    ORDER BY id DESC 
    LIMIT 100) t 
UNION ALL 
    ... and so on ... 
ORDER BY id DESC 
LIMIT 100 

這跑得快。時間戳超出範圍的分區甚至不包括在查詢計劃中。

我的問題是:是否有某種暗示或語法,我可以在Postgres的8.2用於阻止查詢籌辦者通過掃描整個表,但仍使用簡單的語法,只是指主表?

基本上,我是否可以避免動態構建每個正在被定義的分區的UNION查詢的痛苦?

編輯:我已經啓用(感謝@Vinko Vrsalovic)

+1

8.2?真?在做任何事情之前,你應該考慮升級到支持(和當前)的Postgres版本(9.2是當前的版本) – 2013-04-01 15:57:50

回答

3

有你(你鏈接到文檔中的第5.9.4節)試圖約束排除constraint_exclusion

約束排除是查詢 優化技術,其改進了以上述方式定義的分區表 的性能 。作爲一個例子:

SET constraint_exclusion = on; 
SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01'; 

沒有 約束排除,上述查詢 將掃描每個 測量表的分區。啓用約束 排除,規劃將 檢查每個 分區的限制,並試圖證明 分區不需要被掃描,因爲 它不能包含滿足 查詢的WHERE子句中的任何行。當計劃者可以證明這一點時,它會從查詢計劃中排除 分區。

您可以使用EXPLAIN命令 顯示計劃 與constraint_exclusion on和 計劃之間的差異。

+0

是的,我已經開啓了約束排除。不幸的是,主表(總是空的)總是包含在查詢中,因爲它不可能對它應用CHECK約束(至少在8.2中)。這意味着查詢中始終包含至少兩個表 – 2010-02-10 12:48:52

4

我有一個類似的問題,我可以通過在WHERE中投射條件來解決。 EG:(假設TIME_STAMP列timestamptz型)

WHERE time_stamp >= '2010-02-10'::timestamptz and time_stamp < '2010-02-11'::timestamptz 

此外,還要確保餐桌上的CHECK條件是指以同樣的方式... EG: CHECK(TIME_STAMP < '2010-02-10' :: timestamptz)

2

我有同樣的問題,並將其歸結爲兩個原因,在我的情況:

  1. 我已經索引的列類型timestamp WITH time zone以及此列的分區約束,其類型爲timestamp WITHOUT time zone

  2. 修復約束後需要所有子表的ANALYZE

編輯:知識的另一位 - 它要記住,約束排除(允許PG跳過掃描某些表根據您的劃分標準)不工作是很重要的,報價:non-immutable function such as CURRENT_TIMESTAMP

我有CURRENT_DATE的請求,這是我的問題的一部分。