Comments 30
Как упоминалось выше, в каждом кортеже (он же tuple в английской документации) хранятся xmin и xmax. Получается, что в каждый кортеж теперь надо писать не 8 байт, а 16.
А как оно "включается" на уже существующей БД? Поднимается бэкап на версии Postgres c имплементированным 64-bit xid и что потом? Оба столбца каждой строки каждой таблицы апдейтится под новый тип данных или что? Или всё остаётся как есть и только в следующее изменение кортежа меняется тип этих столбцов? Или вообще всё иначе?
Это неточность формулировки. Правильно должно звучать так: надо было бы писать не 8, а 16 (в статье исправил тоже). Именно по этой причине мы не пошли таким путём. Мы храним туплы в старом 32–х битном формате, сохраняя 8 байт ксидов для каждого тупла, но дополнительно размещаем на странице “базу”, сложение с которой и выдаёт нам 8-ми байтный ксид.
Ага! Спасибо! Теперь понятно.
Эта база ведь прибавляется и к xmin, и к xmax всех туплов на этой странице?
А если разница между xmin и xmax туплов на одной странице вдруг станут отличаться больше чем на 4млрд? :) понятно что маловероятная ситуация...
Почему маловероятная? Автор же сам пишет, что 32-биный счетчик за сутки может переполняться. Удалили запись с возрастом два дня - и привет. Или я что-то неправильно понимаю?
Правильно понимаете. Конечно проблема существует и является ограничением текущей реализации. Если базу не получится сдвинуть, то будет ошибка. Но такие ситуации, когда в одном блоке разница между двумя номерами транзакций должна быть меньше 2**32, бывают значительно реже, чем ограничение на разницу 2**31 на всех блоках всего кластера.
При поднятии бэкапа все счётчики сбрасываються и заполняються уже средствами текущего движка СУБД.
Поэтому размерность кортежей в исходной БД роли не играет
postgres плохо подходит для высоконагруженных транзакционных субд в первую очередь вовсе не из-за размерности xid. Главная причина - механизм версионности, который плодит версии строки внутри того же сегмента данных, что приводит к распуханию сегментов данных, потом к необходимости вакуума по тем же страницам данных, а потом и к дефрагментации из-за этого (и необходимости в vacuum full). Это все просто антипаттерн для системы где много изменений в данных. И сравните это с эталоном - Oracle, где старые версии строки хранятся в отдельном сегменте данных undo log, и поэтому: 1. Не распухает основной сегмент данных. 2. Очистка старых версий (вакуум) НЕ мешает работе с основными данными, 3. дефрагментация из-за пустых версий отсутствует. (единственное где из-за этого оракл проиграет - при Rollback-ах. Но много ли их выообще?? )
Это фатальный недостаток который в PG принципиально не излечим
Интересно, не думал об этом.
Можете посоветовать пост/статью на эту тему со сравнением популярных DB?
Ссылки на превосходство «эталона» ничем не обоснованы, так как бенчмарки с участием Оракла без письменного разрешения Оракла законодательно запрещены. Все крупнейшие базы реализованы на различных вариантах mvcc, бенчмарки показывают, что реализация в целом неплохая и конкурентоспособная. Сейчас статьи нет под рукой, но поищу и приложу ссылки на статьи с бенчмарками версионного контроля в базах.
orioledb придёт, порядок наведёт.
Там очень глобальные доработки в ядре и я сильно сомневаюсь что удастся их пропихнуть в основной состав Pg.
А переходить в чистом виде на OrioleDB не каждый решиться без поддержки.
И кстате пока в OrioleDB нельзя создавать индексы отличные от B-Tree, но очень ждем что команда Александра Короткова это решит.
К сожалению да, слабое место postgree на высоких нагрузках это MVCC.
Оракл точно так же на высоких нагрузках поднимает лапки с ORA-01555: snapshot too old. Я бы сказал, что современные СУБД — это ПО с помощью которого можно получать нужные результаты, но только если уметь это делать. Родовые недостатки есть у всех.
Разве этот фатальный недостаток, который принципиально не излечим, не нивелируется CoW?
Стоит добавить что это сделало невозможным использование служебного столбца xmin для разрешения конфликтов доступа в оптимистичной модели Entity Framework Core в .NET. Именно его предлагают использовать в ванильном PostgreSQL для этих целей. Официальный драйвер PostgreSQL логично не может больше смапить этот столбец в Postgres Pro Enterprise на тип unsigned int, потому что ожидается другой тип. И это явилось для нас очень неприятным открытием и послужило отказом от использования Postgres Pro Ent.
Да, есть такое. Но на Майкрософт мы повлиять не можем. С другой стороны, все понимают что рано или поздно в ванилле тип данных тоже изменится, после чего им придется изменить свой драйвер.
P.s. в standart версии ксиды хранятся по старорежимному, так что если нет потребности именно в ent, это не будет проблемой.
Это с скорее к разработчикам драйвера npgsql, но они вряд ли что то будут делать, чего нет в ванили. Кстати в последних версиях он поддерживает тип xid8. Но при попытке создания xmin с этим типом в enterprise через model (code) first, все равно получаю в БД xid, и оно конечно не работает. Надо будет попробовать покопаться во внутрянке драйвера когда будет время, может удастся научить его работать с вашими xid. Некоторые наши заказчики настаивают на использовании именно Postgres Pro Enterprise.
Это называется не «решили проблему», а «отложили проблему на неопределённое время». («Проблема 2000» передаёт горячий привет эстафету «проблеме 2038»).
Хочу использовать поле xmin как номер версии записи в коде go, чтобы случайно не записать в БД устаревшую версию записи из памяти.
Сейчас это бесполезно т.к. 32битный ИД может стать меньше чем был.
Хочу 64битный xmin :-)
Сдается мне что проблема 32-битного счетчика транзакций в большой мере надуманная.
Почему за все годы никто в глобальной pgdg не серьезно задумался об этом?
Скорее всего 99,99% инсталляций не сталкиваются с подобной проблемой даже близко. А в тех случаях когда это все-таки "выстреливает" имело место изначально "кривая" архитектура приложения(АПП и БД в комплексе)
Но даже это не основная проблема. Как упоминалось выше, в каждом кортеже (он же tuple в английской документации) хранятся xmin и xmax. Получается, что в каждый кортеж теперь надо было бы писать не 8 байт, а 16. А при условии что минимальный кортеж — это 24 байта, размер базы начинает стремительно увеличиваться.
Дополню, что проблема более комплексная. Просто добавить по 8 байт к каждой записи — не такая уж большая проблема. Самые объёмные таблицы в современных базах имеют довольно большие по размеру строки и суммарное увеличение от простой замены xmin/xmax на 8-байтные числа повлечёт увеличение размера баз хорошо если на 1-2%. По нынешним меркам это ничножная плата за отсутствие wraparound. Скорее всего современные файловые системы со сжатием вообще не покажут никакой существенной разницы. Сложности в другом. Чтобы сделать такую замену надо поменять формат хранения блоков и, следовательно, переписать всю базу в новый формат. То есть потеря обратной совместимости, до свидания pg_upgrade --link, и вообще быстрое обновление на такой формат невозможно. Для больших баз, а 64-битный счётчик транзакций нужен именно им, это серьёзный аргумент против. Вот и думает сообщество, хитровывернутая математика база+смещение со всей её сложностью и потенциальными проблемами (читай — багами), или таки честные 64 бита с необходимостью тяжёлой миграции на новый формат. А сама необходимость в 64-битном счётчике давно уже очевидна.
Думаю, имеет смысл сразу закладывать возможность дальнейшего расширения, иначе получится очередное "640kb хватит всем"
Будущее PostgreSQL: как 64-битный счетчик транзакций решает проблему масштабирования