последовательность, основанная на идентификаторе компании postgresql - PullRequest
4 голосов
/ 12 января 2011

У меня есть база данных с компаниями и их продуктами, я хочу для каждого Компания должна иметь отдельную последовательность идентификаторов продуктов.

Я знаю, что postgresql не может этого сделать, единственный способ - создать отдельную последовательность для каждой компании, но это громоздко.

Я думал о решении иметь отдельную таблицу для хранения последовательностей

CREATE TABLE "sequence"
(
  "table" character varying(25),
  company_id integer DEFAULT 0,
  "value" integer
)

"таблица" будет содержать имя таблицы для последовательности, такой как продукты, категории и т. Д.

и значение будет содержать фактические данные последовательности, которые будут использоваться для product_id на вставках

Я буду использовать значение UPDATE ... RETURNING; чтобы получить идентификатор продукта

Мне было интересно, эффективно ли это решение?

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

Есть ли лучший способ решить эту проблему?

Я не хочу использовать последовательность для таблицы продуктов для всех компаний, потому что разница между идентификаторами продуктов будет большой, я хочу, чтобы она была простой для пользователей.

Ответы [ 2 ]

3 голосов
/ 12 января 2011

Вы можете просто вставить счетчик в таблицу компаний:

CREATE TABLE companies (
    id          SERIAL PRIMARY KEY,
    name        TEXT,
    product_id  INT DEFAULT 0
);

CREATE TABLE products (
    company     INT REFERENCES companies(id),
    product_id  INT,
    PRIMARY KEY (company, product_id),

    name        TEXT
);

INSERT INTO companies (id, name) VALUES (1, 'Acme Corporation');
INSERT INTO companies (id, name) VALUES (2, 'Umbrella Corporation');

Затем используйте UPDATE ... RETURNING, чтобы получить следующий идентификатор продукта для данной компании:

> INSERT INTO products VALUES (1, (UPDATE companies SET product_id = product_id+1 WHERE id=$1 RETURNING product_id), 'Anvil');
ERROR:  syntax error at or near "companies"
LINE 1: INSERT INTO products VALUES (1, (UPDATE companies SET produc...
                                            ^

О нет! Кажется, вы не можете (начиная с PostgreSQL 9.1) использовать UPDATE ... RETURNING в качестве подзапроса.

Хорошая новость в том, что это не проблема! Просто создайте хранимую процедуру, которая выполняет этап приращения / возврата:

CREATE FUNCTION next_product_id(company INT) RETURNS INT
AS $$
    UPDATE companies SET product_id = product_id+1 WHERE id=$1 RETURNING product_id
$$ LANGUAGE 'sql';

Теперь вставка - кусок пирога:

INSERT INTO products VALUES (1, next_product_id(1), 'Anvil');
INSERT INTO products VALUES (1, next_product_id(1), 'Dynamite');
INSERT INTO products VALUES (2, next_product_id(2), 'Umbrella');
INSERT INTO products VALUES (1, next_product_id(1), 'Explosive tennis balls');

Обязательно используйте один и тот же идентификатор компании как в значении продукта, так и в аргументе next_product_id(company INT).

0 голосов
/ 12 января 2011

В зависимости от того, сколько у вас компаний, вы можете создать последовательность для каждой компании.Запросите его с помощью функции, которая установлена ​​по умолчанию в вашем столбце product_id.

В качестве альтернативы эта функция может просто сделать SELECT FOR UPDATE и обновить значения вашей таблицы.Я думаю, что должен быть довольно быстрым.

...