Sto configurando un nuovo database PostgreSQL 9 che conterrà milioni (o forse miliardi) di righe. Così ho deciso di partizionare i dati usando l'ereditarietà di PostgreSQL.Scelta della regola di partizionamento corretta
ho creato una tabella master come questo (semplificato per esempio):
CREATE TABLE mytable
(
user_id integer,
year integer,
CONSTRAINT pk_mytable PRIMARY KEY (user_id, year)
);
E 10 divisorie tabelle:
CREATE TABLE mytable_0() INHERITS (mytable);
CREATE TABLE mytable_1() INHERITS (mytable);
...
CREATE TABLE mytable_9() INHERITS (mytable);
So che le righe saranno sempre accessibili dall'applicazione utilizzando un unico condizione user_id. Quindi mi piacerebbe diffondere i dati "abbastanza" equamente sulle 10 tabelle usando una regola basata su user_id.
Per query sintonizzare sopra la tabella principale, la mia prima idea era quella di utilizzare un vincolo di controllo modulo:
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);
...
Il problema è che quando interrogo la tabella master "MyTable" con la condizione sulla user_id, PostgreSQL analizzatore di controllare tutte le tabelle e non beneficiano del vincolo di controllo:
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)"
Mentre se uso un classico CHECK CONSTRAINT come questo (e la ripartizione che corrisponde a quella regola):
012.351.641.061.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);
...
si esegue la scansione solo le tabelle che soddisfano la condizione (MyTable e mytable_1 in questo esempio):
"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)"
Ma usando come vincolo di controllo è difficile da mantenere perché la gamma di utenti che saranno popolato nel le tabelle cambieranno nel corso degli anni. migliaia prima, forse milioni o più nel prossimo futuro ...
Quale regola potrei usare per partizionare equamente i miei dati su 10 tabelle che potrebbero trarre vantaggio da un vincolo di controllo in modo che una SELECT sulla tabella master effettui la scansione solo il tavolo giusto ...?
Grazie, Nico