metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2015-05-04 04:14 pm

Firebird vs Postgres vs Oracle, MVCC и очереди

Кто руками трогал Postgres или Oracle (или прочие MVCC СУБД)?

Как они реагируют на такое: в таблице ~1 млн записей, в нее долбятся 2-3-5-10 клиентов, каждый над своим подмножеством записей делает что-то вроде "3/4 записей делаем update, 1/4 удаляем, добавляем еще столько же" и повторять это 24/7. Т.е. антипаттерн "очередь поверх MVCC БД, да еще сделанная через пень-колоду".

Firebird с его реализацией MVCC на такое реагирует нехорошо - накапливается мусор в БД и если, не дай бог, рядом будет длинная транзакция (например бэкап) - то мусора будет охрененно много, после чего какая-то из рабочих транзакций станет собирать мусор, и тоже станет длинной, в результате чего есть шансы поиметь бесконечное накопление мусора и нужно будет отключать рабочие процессы и собирать мусор или же базе будет проще сделать backup-restore (с ключиком -g - отключенной сборкой мусора), чем ждать.

Т.е. при определенном проценте версий записей, сборка мусора в Firebird становится настолько тяжелой по i/o, что прочитать базу целиком один раз без сборки мусора для бэкапа и потом восстановить намного быстрее, чем ждать сборки мусора стандартными механизмами.

Что больше всего смущает в этом - то что сборка мусора на ходу читает базу по кругу какое-то неимоверное количество раз (судя по i/o), т.е. для 100 мб базы может быть прочитано-записано 10-100 гб.

Каждый раз это вызывает желание залезть в кишки сервера и поискать там какой-нибудь неявно окопавшийся алгоритм маляра шлемиеля, потому что оно имеет явно нелинейную зависимость от количества записей в целевой таблице. Или же там что-то вроде нелокальности данных - там не кластерный индекс, соответственно версии записей могут лежать по всему файлу БД как попало, а оно их пытается сканировать линейно.

Еще меня посещает мысль сымитировать MVCC руками, загнать поверх такую же нагрузку и посмотреть, не является ли она принципиально несовместимой с MVCC без втаскивания туда какого-нибудь окасаки или LSM.

PS: Вот собственно описание аналогичной проблемы и ответы на нее http://osdir.com/ml/firebird-db/2013-01
/msg00003.html

[identity profile] falcrum.livejournal.com 2015-05-04 04:33 pm (UTC)(link)
Как-то странно выглядит "1/4 удаляем" - не отсюда проблемы?

[identity profile] metaclass.livejournal.com 2015-05-04 05:32 pm (UTC)(link)
Проблемы тут от любых действий связанных с обновлением/удалением записей, которые нужны другим активным транзакциям, т.е. создающих цепочки версий.

Есть альтернативный вариант реализации: вместо удаления сохраняется текущее значение ID и далее обрабатываются записи после него. Оно в принципе подвержено тем проблемам, которые ты описывал для оракл-кластера (генерация сиквенсов пачкой) но мне некритично, т.к. не оракл, и ID генерятся локально.
А вот что в этом плохого: бэкап БД будет линейно замедлятся, а удаление старых записей создает те же проблемы, только перенося их в обслуживающий процесс (т.е. вместо 100 раз удалить по 100 записей - 1 раз удалять 10000).

Поэтому я пытаюсь осмыслить, это проблема Firebird или принципиальная проблема реализации очередей с транзакциями поверх MVCC.