Как мне ВСТАВИТЬ и ВЫБРАТЬ данные с многораздельными таблицами? - PullRequest
3 голосов
/ 19 июня 2010

Я установил набор разделенных таблиц для документов на http://www.postgresql.org/docs/8.1/interactive/ddl-partitioning.html

CREATE TABLE t (year, a);
CREATE TABLE t_1980 ( CHECK (year = 1980) ) INHERITS (t);
CREATE TABLE t_1981 ( CHECK (year = 1981) ) INHERITS (t);
CREATE RULE t_ins_1980 AS ON INSERT TO t WHERE (year = 1980)
    DO INSTEAD INSERT INTO t_1980 VALUES (NEW.year, NEW.a);
CREATE RULE t_ins_1981 AS ON INSERT TO t WHERE (year = 1981)
    DO INSTEAD INSERT INTO t_1981 VALUES (NEW.year, NEW.a);

Насколько я понимаю, если я ВСТАВЛЯЮ В T (год, а) ЗНАЧЕНИЯ (1980, 5), он перейдет к t_1980, а если я ВСТАВЛЮ В t (год, а) ЗНАЧЕНИЯ (1981, 3), перейти к t_1981. Но мое понимание кажется неправильным. Во-первых, я не могу понять следующее из документов

"В настоящее время не существует простого способа указать, что строки не должны вставляться в основную таблицу. Ограничение CHECK (false) для основной таблицы будет наследоваться всеми дочерними таблицами, поэтому его нельзя использовать для этой цели. Одна возможность состоит в том, чтобы установить триггер ON INSERT в главной таблице, который всегда вызывает ошибку. (В качестве альтернативы такой триггер мог бы использоваться для перенаправления данных в соответствующую дочернюю таблицу вместо использования набора правил, как предложено выше. ) "

Означает ли вышеизложенное, что, несмотря на установку ограничений CHECK и ПРАВИЛ, мне также необходимо создать TRIGGER на главной таблице, чтобы вставки переходили в правильные таблицы? Если бы это было так, какой смысл поддерживать разделение БД? Я мог бы просто настроить отдельные таблицы? Я вставил несколько значений в основную таблицу, и эти строки все еще находятся в основной таблице, а не в унаследованных таблицах.

Второй вопрос. При извлечении строк следует ли выбирать из основной таблицы или мне нужно выбирать из отдельных таблиц по мере необходимости? Как будет работать следующее?

SELECT year, a FROM t WHERE year IN (1980, 1981);

Обновление: Похоже, я нашел ответ на свой вопрос

"Помните, что команда COPY игнорирует правила. Если вы используете COPY для вставки данных, вы должны скопировать данные в правильную дочернюю таблицу, а не в родительскую. COPY запускает триггеры, так что вы можете использовать ее, если вы создаете секционированные таблицы, используя триггерный подход. "

Я действительно использовал COPY FROM для загрузки данных, поэтому ПРАВИЛА игнорировались. Попробую с ТРИГГЕРАМИ.

Ответы [ 3 ]

3 голосов
/ 19 июня 2010

Обязательно попробуйте триггеры.

Если вы думаете, что хотите реализовать правило, не делайте этого (единственное исключение, которое приходит на ум, - это обновляемые представления). См. Эту замечательную статью от depesz для более подробного объяснения.

В действительности Postgres поддерживает разбиение только на стороне чтения. Вы собираетесь настроить метод вставки в разделы самостоятельно - в большинстве случаев TRIGGERing. В зависимости от потребностей и применений иногда бывает проще научить ваше приложение вставлять непосредственно в разделы.

При выборе из разбитых на разделы таблиц вы действительно можете просто ВЫБРАТЬ ... ГДЕ ... в основной таблице, если ваши ограничения CHECK правильно настроены (они в вашем примере) и параметр constraint_exclusion установлен строго.

для 8,4:

SET constraint_exclusion = partition;

Для <8,4: </p>

SET constraint_exclusion = on;

Несмотря на это, мне действительно очень нравится, как Postgres делает это и часто сам его использую.

1 голос
/ 03 февраля 2012

Триггеры определенно лучше, чем правила. Сегодня я поиграл с разбиением материализованной таблицы представления и столкнулся с проблемой решения триггеров. Зачем ? Я использую RETURNING и текущее решение возвращает NULL :) Но вот решение, которое работает для меня - поправьте меня, если я ошибаюсь. 1. У меня есть 3 таблицы, которые вставляются с некоторыми данными, есть представление (пусть мы назовем его viewfoo), которое содержит данные, которые должны быть материализованы. 2. У вставки в последнюю таблицу есть триггер, который вставляет в материализованную таблицу представления через INSERT INTO matviewtable SELECT * FROM viewfoo ГДЕ recno = NEW.recno; Это прекрасно работает, и я использую RETURNING recno; (recno типа SERIAL - последовательность).

Материализованное представление (таблица) должно быть разделено, потому что оно огромно, и в соответствии с моими тестами в данном случае это как минимум в 10 раз быстрее для SELECT. Проблемы с разметкой: * Текущее решение триггера RETURN NULL - поэтому я не могу использовать RETURNING recno. (Текущее решение триггера = триггер объяснен на странице depesz).

Решение: Я изменил триггер моей 3-й таблицы, чтобы НЕ вставлять в материализованную таблицу представления (эта таблица является родителем секционированных таблиц), но создал новый триггер, который вставляет секционированную таблицу непосредственно ИЗ 3-ей таблицы и которая запускает RETURN NEW. Материализованная таблица представления автоматически обновляется, и RETURNING recno работает нормально. Я буду рад, если это кому-нибудь поможет.

1 голос
/ 19 июня 2010

Означает ли вышесказанное, что, несмотря на установить ограничения CHECK и ПРАВИЛА, я также должен создать ТРИГГЕРЫ на главном столе, чтобы ВСТАВКИ идут в правильные таблицы?

Да. Читать пункт 5 (раздел 5.9.2)

Если бы это было так, что было бы точка поддержки БД разделение? Я мог бы просто настроить отдельные таблицы?

В основном: INSERTS в дочерних таблицах должны выполняться явно (либо путем создания TRIGGERS, либо путем указания правильной дочерней таблицы в запросе). Но разметка прозрачен для SELECTS, и (учитывая преимущества этой схемы для хранения и индексации) в этом все дело. (Кроме того, поскольку разделенные таблицы наследуются, схема наследуется от родителя, следовательно, последовательность применяется).

...