Я настраиваю новую базу данных 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.
Поэтому я хотел бы равномерно распределить данные по 10 таблицам, используя правило, основанное на user_id.
Для настройки запросов по основной таблице моей первой идеей было использование ограничения проверки модуля:
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)"
Принимая во внимание, что если я использую классическое ограничение CHECK, как это (и перераспределение, соответствующее этому правилу):
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)"
Но использование такого проверочного ограничения трудно поддерживать, поскольку диапазон пользователей, которые будут заполняться в таблицах, будет меняться с годами. тысячи первых, может быть, миллионы или больше в ближайшем будущем ...
Какое правило я мог бы использовать для равномерного разделения моих данных на 10 таблиц, которые могли бы воспользоваться проверочным ограничением, чтобы SELECT в основной таблице сканировал только нужную таблицу ...?
Спасибо
Nico