Лоренц, во-первых, ты чемпион за то, что копался и помогал мне. Спасибо. Для справки, я задал этот вопрос более подробно в нескольких списках рассылки PG, и получил ноль ответов.Я думаю, что это потому, что мой полный вопрос был слишком длинным.
Я попытался быть здесь короче и, к сожалению, не объяснил важную часть ясно.Физическая оптимизация - это , а не .На самом деле, система commit_timestamp будет стоить мне места, так как это глобальная настройка для всех таблиц.Мои реальные таблицы будут иметь полные timestamptz (установлены в UTC) поля, по которым я буду индексировать и агрегировать.То, что я сейчас пытаюсь разобраться (фаза разработки) - это точность подхода.А именно, собираю ли я все события один раз и только один раз?
Мне нужен надежный последовательный номер или временная линия , чтобы отметить самую высокую / последнюю строку, которую я обработал, и текущую самую высокую/ последний ряд.Это позволяет мне захватывать любые строки, которые не были обработаны, без повторного выбора уже обработанных строк или блокировки таблицы при добавлении новых строк.Эта идея называется «идентификатором параллелизма» в некоторых контекстах.Вот эскиз, адаптированный из другой части нашего проекта, в котором было целесообразно использовать числа вместо временных меток (но временные шкалы - это тип числовой линии):
Д'оо!Я не могу публиковать изображения.Это здесь:
https://imgur.com/iD9bn5Q
Показывает номерную строку для отслеживания записей, которые делятся на три части [Готово] [Захватить их] [Хвосты]
«Готово»это все из самого высокого / последнего обработанного счетчика.
«Захватить это» - это все, что позже «Готово» и меньше текущего максимального счетчика в таблице.
«Хвост» - любой новыйболее высокие счетчики добавляются другими входными данными во время обработки строк «захвата этих».
На снимке это легче увидеть.
Итак, у меня есть небольшая служебная таблица, такая какэто:
CREATE TABLE "rollup_status" (
"id" uuid NOT NULL DEFAULT extensions.gen_random_uuid(), -- We use UUIDs, not necessary here, but it's what we use.
"rollup_name" text NOT NULL DEFAULT false,
"last_processed_dts" timestamptz NOT NULL DEFAULT NULL); -- Marks the last timestamp processed.
А теперь представьте одну запись:
rollup_name last_processed_dts
error_name_counts 2018-09-26 02:23:00
Итак, моя числовая строка (временная шкала, в случае фиксации времени) обрабатывается с любой даты 0до 2018-09-26 02:23:00В следующий раз я получу текущий максимум из интересующей меня таблицы 'scan':
select max(pg_xact_commit_timestamp(xmin)) from scan; -- Pretend that it's 2019-07-07 25:00:00.0000000+10
Это значение становится верхней границей моего поиска, и новое значение rollup_status.last_processed_dts.
-- Find the changed row(s):
select *
from scan
where pg_xact_commit_timestamp(xmin) > '2019-07-07 20:46:14.694288+10' and
pg_xact_commit_timestamp(xmin) <= '2019-07-07 25:00:00.0000000+10
Это сегмент "захватить эти" моей числовой линии.Это также единственное использование, которое я запланировал для данных о времени фиксации.Мы загружаем данные из различных источников и хотим, чтобы их метки времени (с учетом UTC), а не метки времени сервера.(Серверные временные метки могут иметь смысл, в случае наших данных они просто не случаются.) Таким образом, единственная цель временной метки фиксации - создать надежную числовую линию.
Если вы посмотрите на график, он показывает три разные числовые линии для одной и той же базовой таблицы.Сама таблица имеет только один номер или временную шкалу, есть три различных использования этого номера / временного ряда.Итак, три строки rollup_status, идущие с моей таблицей эскизов из ранее.Таблица «scan» должна ничего не знать о том, как она используется.Это огромное преимущество этой стратегии.Вы можете добавлять, удалять и повторять операции без необходимости изменять основную таблицу или ее строки.
Я также рассматриваю триггер выбора ON AFTER INSERT / UPDATE с таблицей переходов для заполнения timestamptz (установлен на UTC), как row_commmitted_dts.Это может быть мой план B, но он требует добавления триггеров, и кажется, что он может быть только немного менее точным, чем фактическое время транзакции.Вероятно, небольшая разница, но с параллелизмом, небольшие проблемы могут быстро перерасти в большие ошибки.
Итак, вопрос в том, могу ли я рассчитывать на систему фиксации времени для получения точных результатов, которые не появятся «в прошлом». Вот почему я не могу использовать идентификаторы транзакций. Они назначаются в начале транзакции, но могут быть зафиксированы в любом порядке. (Насколько я понимаю.) Поэтому мои границы диапазона «последний обработанный» и «текущий максимум в файле» не могут работать. Я мог получить этот диапазон, и ожидающая транзакция могла зафиксировать тысячи записей с отметкой времени ранее , чем мое ранее записанное «максимальное значение». Вот почему я за марками коммитов.
Опять же, спасибо за любую помощь или предложения. Я очень благодарен.
P.S Единственная дискуссия, с которой я столкнулся в мире Postgres с чем-то вроде этого, здесь:
Масштабируемое добавочное агрегирование данных на Postgres и Citus.
https://www.citusdata.com/blog/2018/06/14/scalable-incremental-data-aggregation/
Они используют счетчики больших серий таким образом, но, насколько я понимаю, это работает только для INSERT, а не UPDATE. И, честно говоря, я недостаточно знаю о транзакциях и сериалах Postgres, чтобы продумать поведение параллелизма.