2011-11-25 57 views
5

我設置的是將包含行的數百萬(或數十億可能)一個新的PostgreSQL 9數據庫。所以我決定使用PostgreSQL繼承分區數據。選擇正確的分區規則

我創建了一個主表這樣的(簡化的舉例):

CREATE TABLE mytable 
(
    user_id integer, 
    year integer, 
    CONSTRAINT pk_mytable PRIMARY KEY (user_id, year) 
); 

而10的分區表:

CREATE TABLE mytable_0() INHERITS (mytable); 
CREATE TABLE mytable_1() INHERITS (mytable); 
... 
CREATE TABLE mytable_9() INHERITS (mytable); 

我知道行將總是從使用唯一的應用程序訪問user_id條件。 因此,我想使用基於user_id的規則在10個表格上「相當」地分佈數據。

要在主表優化查詢,我的第一個想法是使用一個模檢查約束:

ALTER TABLE mytable_0 ADD CONSTRAINT mytable_user_id_check CHECK (user_id % 10 = 0); 
ALTER TABLE mytable_1 ADD CONSTRAINT mytable_user_id_check CHECK (user_id % 10 = 1); 
... 

的問題是,當我查詢主表「MYTABLE」與USER_ID,PostgreSQL的條件分析檢查所有的表,不從檢查約束受益:

EXPLAIN SELECT * FROM mytable WHERE user_id = 12345; 

"Result (cost=0.00..152.69 rows=64 width=36)" 
" -> Append (cost=0.00..152.69 rows=64 width=36)" 
"  -> Seq Scan on mytable (cost=0.00..25.38 rows=6 width=36)" 
"    Filter: (user_id = 12345)" 
"  -> Seq Scan on mytable_0 mytable (cost=0.00..1.29 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 
"  -> Seq Scan on mytable_1 mytable (cost=0.00..1.52 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 
... 
"  -> Seq Scan on mytable_9 mytable (cost=0.00..1.52 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 

而如果我用一個經典的檢查約束這樣的(和匹配規則,即重新分配):

ALTER TABLE mytable_0 ADD CONSTRAINT mytable_user_id_check CHECK (user_id BETWEEN 1 AND 10000); 
ALTER TABLE mytable_1 ADD CONSTRAINT mytable_user_id_check CHECK (user_id BETWEEN 10001 AND 20000); 
... 

它會掃描只匹配條件(mytable的和mytable_1在本例中),該表:

"Result (cost=0.00..152.69 rows=64 width=36)" 
" -> Append (cost=0.00..152.69 rows=64 width=36)" 
"  -> Seq Scan on mytable (cost=0.00..25.38 rows=6 width=36)" 
"    Filter: (user_id = 12345)" 
"  -> Seq Scan on mytable_1 mytable (cost=0.00..1.52 rows=1 width=36)" 
"    Filter: (user_id = 12345)" 

但是,使用這樣的檢查約束難以維持,因爲這將在被填充的用戶範圍表格將在多年內發生變化。成千上萬的第一,甚至幾百萬或更多在不久的將來...

我可以用什麼規則來劃分同樣我了,可以受益於一個檢查約束,以便在主表中的SELECT將只掃描了10個表中的數據正確的桌子......?

感謝, 尼科

回答

5

該限制是策劃者,而不是partioning本身。它覆蓋在一些細節的手冊:

http://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

有你提到,雖然必須考慮到需要兩件事情。

首先,你說的所有的訪問都將通過主鍵。這意味着您將不會從分區中獲得性能優勢(至少不會在正常使用情況下)。每個分區上的索引會更小,但PG需要選擇首先檢查哪個分區。如果你需要重新索引或類似的地方,你將獲得的是 - 你可以分別重新索引每個分區。

其次,你說你可能從幾千到數十億行的任何東西。這使我得出兩個結論:

  1. 也許稍後再決定。等到你需要分區。
  2. 你不可能希望有兩千行兩十億正好10個分區。

如果您打算進行分區,請按範圍進行操作 - 比方說100,000個行或每個分區100萬個。添加一個cron作業,檢查使用的最大ID,如果需要(每天一次也許)創建新的分區。

就個人而言,雖然,我會離開它,直到我需要它。也許只有一個分區作爲一個包羅萬象的,如果你認爲它更可能不是你以後會需要它們。

1

WHERE需要是在相同的表達式作爲CHECK島即,查詢規劃不會意識到user_id = 12345允許的結論是user_id % 10 = 5。嘗試

EXPLAIN SELECT * FROM mytable WHERE user_id = 12345 AND user_id % 10 = 5; 

這麼說,我想第二Richard Huxton's answer中,你可能要推遲分區,直到你對數據集的大小更多信息,日eidea是避免過早的優化。 Postgres的可以在相當大的表非常快,它會帶你很遠的不分區。