🐘 Подготовленные планы в PostgreSQL
Кто-то меня спрашивал о выгоде преподготовленных планов в «Постгресе». Наши испытания показывают, что выигрыш порядка 10—15%, что очень немало. И я уже рассказывал, что придумал рецепт как делить их в условиях «умирающего» ПХП.
Но вот какая неприятность — при подключении любого балансировщика нагрузки, совершенно неочевидно куда улетает ваш план и таблица в приложении не помогает — она единая, а серверов может быть несколько, у каждого свои планы подготовленные. Если мы начнём подготавливать его заново, а он уже есть, получим ошибку, что план уже существует.
Какой выход? Краткий ответ: пока никакой.
Самый очевидный — игнорировать такие ошибки. К сожалению, он не подойдёт — если ошибка произойдёт в транзакции, «Постгрес» её просто откатит. Второй выход — не использовать подготовленные планы. Я пока нашёл третий — мы используем планы только если уверены, что они пойдут на мастер — это запросы на изменение чего-либо.
С другой стороны у меня появилась идея — добавить в эскуэль конструкцию PREPARE IF NOT EXISTS, ребята из, с которыми я обсуждал эту идею, PostgresPro уже сделали несколько версий патча.
Основа идеи — всегда слать запрос на компиляцию плана, но если он уже был скомпилирован, ничего не делать. Мы его уже погоняли (оттуда и цифры первого абзаца), но на этом пути больше трудностей, чем себе можно представить — в частности, надо патчить ещё и продукты для балансировки и расширять его клиентский протокол.
Очень надеюсь, что патч доведут до ума и мы скоро сможем его использовать.
А делать savepoint перед такими запросами на поготовку запросов и делать rollback to savepoint если произошла ошибка сильно дольше, чем выигрыш от подготовки?
Комментарий для pavelpat:
Во-первых, правильное решение, всё же — предоставить возможность не подготавливать планы, если они уже готовы. Тем более, это в традициях Постгреса — что-то похожее есть почти во всех командах создания чего-либо.
Во-вторых, как ты думаешь, какова сложность операции отката/накатки транзакции и репликации всего этого? Не думаю, что стоит даже начинать копать в этом направлении.
Я не знаю что такое планы в постгресе, но ведь можно делать вместо ’plan_name’ костыль ’server_0_plan_name’, на каждый сервер будет хранится своя копия плана
Комментарий для hshhhhh.name:
Как узнать сервер?
Комментарий для hshhhhh.name:
Планы в «Постгресе» то же, что и в любой другой базе.
Не могу ответить однозначно, но думаю, что данные попадают на реплики только после коммита всей транзакции, а savepoint на этот механизм никак не влияет.
Насчёт стоимости savepoint’а, ниразу не слышал, что этот механизм не стоит использовать из-за каких-то проблем с производительностью. Считаю, что этот вопрос нужно изучить, прежде чем отвечать.
Комментарий для Евгения Степанищева:
Обидно еще то, как я понимаю, подготовленный план гораздо выгоднее в сложных селектах?
Комментарий для Олег Горбунов:
Да, конечно!
Комментарий для pavelpat:
В тех местах, где его стоит применять, никакого выбора нет. Там так не стоит вопрос.
Ну что ж, изучай.
Надо будет сохранить этот пост и давать на него ссылку при вопросе «почему PHP не подходит для production».
Простейшие для нормальных языков вещи- и делаются через ж..у.
PS: поэтому и ctrl+enter не отправяет комментарий? :D
А причём тут именно php? То, что пулер коннекшнов может кинуть вас на другой сервер, где prepared statement-а ещё нет, как-то относится к пхп?
Евгений, а почему нельзя просто использовать PgBouncer в режиме «Session pooling» для пула, а в конце каждой сессии делать DEALLOCATE подготовленного запроса? Разве это не решит проблему?
Комментарий для Евгения Степанищева:
pgbouncer позволяет при коннекте выполнять определенный запрос, можно запихнуть туда вызов функции, которая создаст все нужные планы
Комментарий для alxt:
А как в других языках это сделать? Как какая-то нибудь Java узнает куда pgpool кинул запрос?
Да ленюсь всё починить :)
Комментарий для pavelpat:
Это убъёт всю идею кеширования планов — всё будет парситься заново.
Комментарий для silent:
Как узнать какие планы нужные?
Комментарий для Евгения Степанищева:
всегда есть какие-то наиболее частые и сложные запросы в системе, обычно для них планы и строят
Комментарий для silent:
Да их сотни. И планы надо на всё строить, что с биндами.
А зачем знать, если у меня пулл потоков, а не дохнущие одноразовые? Можно вообще не заморачиваться — будет прогрев нескоько дольше, и всё.
Комментарий для alxt:
Вы внимательно всё перечитайте. Разговор как раз о не дохнущих соединениях и о том, что приложение не знает куда pgpool кинет запрос и подготовлен он уже там или нет.