PostgreSQL увеличивает значения строк в таблице - PullRequest
1 голос
/ 23 апреля 2011

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

Чтобы дать вам картину, скажем, у нас есть таблица:

CREATE TABLE statistics(
  user_id      integer NOT NULL,
  date         integer NOT NULL, -- for unix time
  stat1        integer NOT NULL DEFAULT 0,
  stat2        integer NOT NULL DEFAULT 0,
  stat3        integer NOT NULL DEFAULT 0  -- and so on...
);

-- Let's insert some testing data for a couple of users and days...
-- Day one
INSERT INTO statistics(1, 1303520820, 1, 1, 1);
INSERT INTO statistics(2, 1303520820, 1, 1, 1);
-- Day two
INSERT INTO statistics(1, 1303603200, 1, 1, 1);
INSERT INTO statistics(2, 1303603200, 1, 1, 1);
-- Day three
INSERT INTO statistics(1, 1303689600, 1, 1, 1);
INSERT INTO statistics(2, 1303689600, 1, 1, 1);

Каждый день в таблицу добавляется новая строка, чтобы мы моглиежедневная, еженедельная, ежемесячная, годовая статистика.Я должен быть уверен, что только одна строка вставляется в user_id в день.Также всякий раз, когда выполняется запрос UPDATE, он будет соответственно увеличивать столбцы stat1 , stat2 , stat3 .

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

Ответы [ 3 ]

3 голосов
/ 23 апреля 2011

Самое простое решение - добавить уникальное ограничение

CREATE TABLE statistics(
  user_id      integer NOT NULL,
  date         integer NOT NULL, -- for unix time
  stat1        integer NOT NULL DEFAULT 0,
  stat2        integer NOT NULL DEFAULT 0,
  stat3        integer NOT NULL DEFAULT 0,  -- and so on...
  UNIQUE(user_id,date)
);

Вы должны определенно делать это независимо от того, какие другие меры вы принимаете.

1 голос
/ 15 октября 2015

Также вы можете добавить CHECK для значения даты, чтобы обеспечить кратность 1 дня:

ALTER TABLE "statistics" ADD CONSTRAINT "1day_quantum" CHECK ("date" = ("date" / 86400)::INTEGER * 86400);

Тогда будет выдано исключение, если одна попытка вставить неправильное значение даты.

Если тип поля даты будет TIMESTAMP или TIMESTAMPTZ, то CHECK более сложный:

ALTER TABLE "statistics" ADD CONSTRAINT "1day_quantum" CHECK ("date" = TIMESTAMP 'epoch' + ((EXTRACT(EPOCH FROM "date") / 86400)::INTEGER * 86400) * INTERVAL '1 second');

Изменяя 86400 (количество секунд), вы можете настроить ограничение на различное количество: например, 900 для 15 минут.

1 голос
/ 23 апреля 2011

Вам нужно уникальное ограничение для пары user_id и date, как уже говорили другие.

Чтобы вставить без выполнения арифметики, когда составной ключ (user_id, date) не существует, и для обновления с помощью арифметики, когда составной ключ действительно существует, необходимо написать несколькокод.Неформально это называется «упасть».Существует несколько способов.

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

Вы можете (я думаю) использовать suppress_redundant_updates_trigger () .Преимущество триггеров заключается в том, что они не могут быть случайно обойдены кодом приложения или девушками из базы данных.Я не использовал эту технику сам, поэтому я не могу комментировать дальше.Этот триггер задокументирован здесь .

Вы также можете обрабатывать логику восходящего потока с помощью пользовательского триггера .

...