Теоретический вопрос по PG

Зл0й
Дата: 13.09.2004 05:19:20
Насколько я понял из документации, PG - версионник. Есть еще такой зверь как Vacuum который осуществляет "сборку мусора" на диске. Хочется понять с точки зрения концепции, как это работает.

Допустим прошла такая тразакция Т1: мы сделали update после чего прибили его commit.
- старая версия записи осталась доступной (пока vacuum до нее не доберется)
- новая версия стала доступна
- есть некий механизм который запросам начавшимся до Т1 выдаст старую версию, а запросам начавшимся после Т1 выдаст новую.

То есть, концептуально мы превращаем update в insert, а старая версия записи живет пока до нее не доберется "сборщик мусора". Просьба исправить, если я чего-то неправильно понял.
nevermind
Дата: 13.09.2004 12:23:49
Ты наверное забыл указать источник ;) http://www.postgresql.org/docs/aw_pgsql_book/node110.html
Зл0й
Дата: 13.09.2004 21:03:23
Насколько я понял, переход PG поддерживает WAL - упреждающую запись в логи. К чему приводит сборка мусора на активно испульзуемой системе, я думаю объяснять не требуется. Этакий "тормоз вестингауза". Если мусор не собирать, то PG жрет место на диске "like there is no tomorrow". Никто не в курсе, а в более новых версиях нет желания отказаться от идеологии "update это на самом деле insert" в пользу изменения блока/страницы где запись лежит, как это сделано в коммерческих СУБД, тем более что WAL позволяет это сделать? Или pls киньте ссылкой где про планы на будущее почитать.
Sad Spirit
Дата: 13.09.2004 21:31:43
Сборка мусора бывает разная. Щас в Postgres есть просто VACUUM и VACUUM FULL. Первый просто помечает место, занятое устаревшими (т.е. не видимыми уже ни одной транзакцией) записями, как свободное, потом на это место могут писаться новые записи. Второй реально собирает мусор, с уменьшением размера файла таблицы на диске.
Зл0й
Дата: 13.09.2004 22:33:48
Чисто концептуально при обработке транзакции типа begin transaction; update ... ; commit; имеем следующие подходы.

Подход первый

Превращаем update в insert. Соответственно где-то должен храниться атрибут указывающий на то в какой момент времени данная запись была актуальной. И при выполнении запроса мы будем вынуждены фильтровать данные по этому атрибуту. Ибо MVCC.

Имеем некий процесс P1, асинхроный по отношению к обработке потока транзакций. Он проверяет не актуальные на момент его запуска записи. Если нет транзакций начавшихся до "устаревания" этих записей, то запись никому не нужна. Процесс помечает ее как "свободное место" на которое можно писАть.

Имеем еще один процесс P2, асинхронный к обработке потока транзакций. Он перемещает актуальные записи на "свободное место" и тем самым уплотняет/высвобождает место.

Подход второй

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

Если СУБД MVCC то мы старую версию данных куда-то пишем (в лог, в rollback segment). Если СУБД - блокировщик, то можно частично сэкономить на записи undo, писать ровно столько сколько необходимо для восстановления.

В общем тут возможны варианты. Проверять для каждого update наличие долгоиграющих читателей, которым может потребоваться старая версия данных ИМХО дороговато. Соответственно можно просто тупо и злобно писать пока хватает rollback segment, а потом поверх как Oracle. Можно писать/высвобождать поумнее, по мере необходимости. Вопрос в том насколько дорого это обойдется по ресурсам.

ИМХО второй подход продуктивнее, поскольку миграция записей по диску мероприятие недешевое, и должна быть сведена к минимуму. К тому же мы 3 раза читаем одну и ту же запись, причем со сдвигом по времени, так что возможно что все 3 раза мы читаем ее с диска а не из буфферного кэша. В первом подходе у нас table storage заодно играет роль лога. Во втором "отдельно мухи, отдельно котлеты". ИМХО разделение логов и страниц с данными - правильно. Ибо природа доступа к ним разная.

С удовольствием выслушаю конструктивную критику, и аргументы за и против технического характера.