Я хотел бы создать веб-службу, которая позволяет клиенту извлекать все строки в таблице, а затем позволяет клиенту получать только новые или обновленные строки.Отправка только обновленных строк клиенту
Простейшая реализация, похоже, заключается в отправке текущей метки времени клиенту, а затем попросите клиента запросить строки, которые являются более новыми, чем метка времени в следующем запросе.
Похоже, что это можно сделать, сохранив столбец «updated_at» с отметкой времени, установленной в NOW(), в обновлении и вставке триггеров, а затем запросив более новые строки, а также передав значение NOW().
Проблема заключается в том, что если есть незавершенные транзакции, эти операции будут устанавливать updated_at ко времени старта сделки, не времени фиксации.
В результате эта простая реализация не работает, поскольку строки могут быть потеряны, поскольку они могут появляться с отметкой времени в прошлом.
Мне не удалось найти простого решения этой проблемы, несмотря на то, что это кажется очень распространенной потребностью: любые идеи?
Возможные решения:
Keep монотонную временную метку в виде таблицы, обновлять его в начале каждой транзакции до MAX (теперь(), last_timestamp + 1) и использовать его в качестве строки метки времени. Проблема: это эффективно означает, что все транзакции записи полностью сериализованы и блокируют всю базу данных, так как они конфликтуют в таблице времени обновления.
В конце транзакции добавьте сопоставление от NOW() к времени в таблице обновлений, как описано выше. Кажется, это требует явного блокирования и использования последовательности для создания невременных «временных меток», потому что просто использование UPDATE в одной строке приведет к откатам в режиме SERIALIZABLE.
Как-то у PostgreSQL, время фиксации, перебрать все обновленные строки и установить updated_at к монотонному метки времени
Как-то есть сам PostgreSQL поддерживать таблицу транзакции раз, что он, кажется, не делать на данный момент
Использование встроенного столбца xmin также представляется невозможным, поскольку VACUUM может удалить его.
Было бы неплохо иметь возможность сделать это в базе данных без изменений ко всем обновлениям приложения.
Как это обычно делается?
Проблема с наивными решениями
В случае это не очевидно, что это проблема с использованием NOW() или CLOCK_TIMESTAMP():
- Во время 1, мы проводим сейчас () или CLOCK_TIMESTAMP() в транзакции, которая дает 1, и мы обновляем время установки строки 1 как время обновления
- В момент 2 клиент извлекает все строки, и мы сообщаем ему, что мы дали все строки до момента времени 2
- В момент 3 транзакция фиксируется с «временем 1» в поле updated_at
- Клиент запрашивает обновленные строки со времени 2 (время, которое он получил от предыдущего запроса полной выборки), мы запрашиваем update_at> = 2, и мы не возвращать, вместо того, чтобы вернуться в строке, которая только что добавил
- Этой строка теряется и никогда не видела клиент
Это еще не время фиксации, поэтому оно не будет работать. То есть транзакция может совершить секунду после вызова функции clock_timestamp(), и обновление теряется, если клиент обновляется тем временем. –
Это не работает по той же причине (если вы не сделаете это под замком). –
Запуск этой точной проблемы, а также поиск ответов. –