PostgreSQL одновременное увеличение счетчика

9

Мне нужно вести статистическую таблицу для проекта, составленную из списка элементов и их использования (Подумайте о чем-то вроде веб-сайта, на котором вы хотели бы подсчитывать просмотры страниц). Каждый раз, когда создается элемент, мне нужно увеличивать использование определенного элемента.

Моя первая реализация:

statistics(
  id      integer NOT NULL,
  name    character varying(255) NOT NULL,
  usage   integer NOT NULL DEFAULT 0,
);


UPDATE statistics 
  SET usage = usage + 1
WHERE name = '<name>';

Мои опасения касаются производительности и параллелизма. Процесс обновления будет реализован несколькими десятками (может быть, 80-120) устройств и может происходить несколько раз в секунду, поэтому мои вопросы:

1) сохранит ли этот метод параллелизм? (т.е. если более одного устройства запрашивают обновление «одновременно», будет ли учитываться каждый запрос?)

2) Можете ли вы предложить лучший способ достижения результата? Я ожидаю, что у меня будет нагрузка при написании обновлений, в то время как чтение будет гораздо более частым. Существует ли специальная функция для увеличения значений? Я смотрю на «последовательность», но я не уверен, что это правильный путь ...

Заранее большое спасибо за любые советы

eng.student
источник

Ответы:

5

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

Предположим, две параллельные транзакции обновляют одну и ту же строку с начальным значением 0

Время перехода 1 значение T1 Транзакция 2 значение T2
-------------------------------------------------- ------------
1 обновление ... 1 0
2 1 обновление .. "undefined"
                                (ожидание) 
3 совершить 1 2
4 1 коммит 2
5 2 2 

«Значение T1» и «Значение T2» означает значение, которое видит эта транзакция.

Если вы хотите убедиться, что вы ловите ситуации, в которых есть «несовместимые» изменения (например, одна транзакция, устанавливающая в usageстолбце определенное значение, а не просто увеличивает его), вы можете перевести все транзакции на «сериализуемый» уровень изоляции. Но тогда вам нужно будет подготовиться к обработке ошибок.

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

SELECTs никогда не будет заблокирован, но будет видеть только соответствующие значения.

a_horse_with_no_name
источник