Postgres: производительность и правильность обходного решения по наследству с внешним ключом - PullRequest
3 голосов
/ 22 августа 2011

Я пытаюсь построить свою первую схему базы данных Postgres, включающую наследование. Мне известно о проблеме с внешним ключом, о которой говорилось в Внешний ключ PostgreSQL не существует, проблема наследования? . Однако ответы на этот вопрос на самом деле не дали пример для решения, поэтому я придумал свой собственный (вдохновленный http://people.planetpostgresql.org/dfetter/index.php?/archives/51-Partitioning-Is-Such-Sweet-Sorrow.html):

CREATE TABLE a (
    id  SERIAL PRIMARY KEY INITIALLY DEFERRED,
    foo TEXT
);

CREATE TABLE b (
    PRIMARY KEY(id),
    a_number REAL
) inherits(a);

CREATE TABLE c (
    PRIMARY KEY(id),
    a_number INTEGER
) inherits(a);

-- SELECT * FROM ONLY a; will always return an empty record.

CREATE TABLE  x (
    a_id INTEGER NOT NULL,
    bar  TEXT
);

CREATE TABLE  xb (
    FOREIGN KEY( a_id ) REFERENCES b INITIALLY DEFERRED
) inherits(x);

CREATE TABLE  xc (
    FOREIGN KEY( a_id ) REFERENCES c INITIALLY DEFERRED
) inherits(x);

Для выполнения работы INSERT INTO x я определил следующий триггер:

CREATE FUNCTION marshal_x()
    RETURNS TRIGGER
    LANGUAGE plpgsql
    AS $$
        DECLARE
            ref_table varchar;
        BEGIN
            SELECT INTO ref_table p.relname FROM a, pg_class p WHERE a.id = NEW.a_id AND a.tableoid = p.oid;

            IF ref_table = 'b'
                THEN INSERT INTO xb ( a_id, bar ) VALUES ( NEW.a_id, NEW.bar );
            ELSIF ref_table = 'c'
                THEN INSERT INTO xc ( a_id, bar ) VALUES ( NEW.a_id, NEW.bar );
            END IF;
            RETURN NULL;
        END;
    $$;

CREATE TRIGGER insert_x_trg
    BEFORE INSERT ON x
    FOR EACH ROW
        EXECUTE PROCEDURE marshal_x();

РЕДАКТИРОВАТЬ: Кто-нибудь видит проблемы с этим определением, которые не очевидны для моего неподготовленного глаза? Предположим, что таблица c пуста. Будет ли производительность

SELECT * FROM a JOIN x ON a.id= x.a_id;

будет таким же, как

SELECT * FROM b JOIN x ON b.id= x.a_id;

? Большое спасибо заранее.

Isam

1 Ответ

2 голосов
/ 31 августа 2011

Какова цель использования наследования в любом случае?Если вам просто нужны разные столбцы в зависимости от типа строки, как в ООП, лучше использовать одну таблицу и поместить NULL в столбцы, которые не применимы.Или разделите дополнительные столбцы в другой таблице, которую вы присоединяете к исходной.

Основное использование наследования в PostgreSQL - это разбиение таблиц, и существует ряд предостережений с наследованием.PostgreSQL 9.1 представляет оптимизацию «Добавление слиянием», которая несколько помогает, но все еще неоптимальна.

SELECT * FROM JOIN x ON a.id = x.a_id;

Объединение двух унаследованных таблиц с большим числом элементов выглядит так, как будто это не очень хорошо масштабируется, особенно когда вы увеличиваете количество дочерних таблиц.PostgreSQL не настолько умен, чтобы соблюдать ограничения внешнего ключа xb и xc, он попытается объединить всю таблицу a со всей x .

Ноопять же, это может оказаться не проблемой, все зависит от ваших запросов и ожиданий производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...