Я не могу говорить о самом Perl-интерфейсе на стороне клиента, но могу пролить свет на сторону сервера PostgreSQL.
PostgreSQL подготовил операторы и неподготовленные операторы.Неподготовленные утверждения анализируются, планируются и исполняются немедленно.Они также не поддерживают подстановку параметров.В простой оболочке psql
вы можете отобразить их план запроса следующим образом:
tmpdb> explain select * from sometable where flag = true;
С другой стороны, есть подготовленные операторы: они обычно (см. «Исключение» ниже) анализируются и планируются за один шаги выполняется на втором этапе.Их можно выполнить несколько раз с разными параметрами, поскольку они делают поддерживают подстановку параметров.Эквивалент в psql
таков:
tmpdb> prepare foo as select * from sometable where flag = $1;
tmpdb> explain execute foo(true);
Вы можете увидеть, что план отличается от плана в неподготовленном утверждении, потому что планирование уже имело место на этапе prepare
, как описано вдокумент для PREPARE :
Когда выполняется инструкция PREPARE, указанным оператором является синтаксический анализ , перезаписанный, и плановый .Когда команда EXECUTE впоследствии выдана, подготовленный оператор должен быть только выполнен.Таким образом, этапы синтаксического анализа, перезаписи и планирования выполняются только один раз, а не каждый раз, когда выполняется оператор.
Это также означает, что план NOT оптимизирован длязамещенные параметры: в первых примерах может использоваться индекс для flag
, потому что PostgreSQL знает, что из миллиона записей только десять имеют значение true
.Такое рассуждение невозможно, когда PostgreSQL использует подготовленное утверждение.В этом случае создается план, который будет работать для всех возможных значений параметров настолько хорошо, насколько это возможно.Это может исключить упомянутый индекс, поскольку выборка лучшей части полной таблицы с помощью произвольного доступа (из-за индекса) медленнее, чем обычное последовательное сканирование.Документ PREPARE подтверждает это:
В некоторых ситуациях план запроса, созданный для подготовленного оператора, будет хуже плана запроса, который был бы выбран, если бы оператор былпредставлены и выполнены нормально.Это связано с тем, что, когда оператор планируется и плановик пытается определить оптимальный план запроса, фактические значения любых параметров, указанных в операторе, недоступны.PostgreSQL собирает статистику о распределении данных в таблице и может использовать постоянные значения в выражении, чтобы угадать вероятный результат выполнения этого выражения.Поскольку эти данные недоступны при планировании подготовленных выписок с параметрами, выбранный план может быть неоптимальным.
Кстати: что касается кэширования плана, в документе PREPARE также есть что сказать:
Подготовленные операторы действуют только в течение текущего сеанса базы данных.Когда сеанс заканчивается, подготовленный оператор забывается, поэтому перед повторным использованием он должен быть воссоздан.
Также отсутствует автоматическое кэширование плана и кэширование / повторное использование для нескольких соединений.
ИСКЛЮЧЕНИЕ : Я упомянул "обычно".Показанные psql
примеры - это не то, что действительно использует клиентский адаптер, такой как Perl DBI.Он использует определенный протокол .Здесь термин «простой запрос» соответствует «неподготовленному запросу» в psql
, термин « расширенный запрос » соответствует «подготовленному запросу» с одним исключением: существует различие между (одним)безымянный оператор "и (возможно, несколько)" именованные операторы ".Что касается именованных операторов, то doc говорит:
Именованные подготовленные операторы также могут быть созданы и доступны на уровне команд SQL, используя PREPARE и EXECUTE.
а также:
Планирование запроса для именованных объектов подготовленного оператора происходит при обработке сообщения Parse.
Таким образом, в этом случае планирование выполняется без параметров, как описано выше для PREPARE
- ничего нового.
Упомянутое исключение - "неназванное утверждение". Док говорит:
Неименованный подготовленный оператор также планируется во время обработки Parse , если в сообщении Parse не определены параметры . Но если есть параметры, планирование запросов происходит каждый раз, когда предоставляются параметры Bind. Это позволяет планировщику использовать фактические значения параметров, предоставляемых каждым сообщением Bind, а не использовать общие оценки.
И здесь есть преимущество: хотя безымянный оператор «подготовлен» (т. Е. Может иметь подстановку параметров), он также может адаптировать план запроса к фактическим параметрам.
Кстати: точная обработка безымянного оператора несколько раз менялась в прошлых выпусках сервера PostgreSQL. Вы можете найти старые документы для деталей, если вы действительно хотите.
Обоснование - Perl / любой клиент :
Как клиент , такой как Perl, использует протокол - это совершенно другой вопрос. Некоторые клиенты, такие как драйвер JDBC для Java, в основном говорят: даже если программист использует подготовленный оператор, первые пять (или около того) выполнений внутренне сопоставляются с «простым запросом» (то есть фактически неподготовленным), после чего драйвер переключается на « именное заявление ".
Таким образом, у клиента есть следующие варианты:
- Принудительное (пере) планирование каждый раз с использованием протокола «простого запроса».
- Планируйте один раз, выполняйте несколько раз, используя протокол «расширенного запроса» и «именованный оператор» (план может быть плохим, потому что планирование выполняется без параметров).
- Разбор один раз, планирование для каждого выполнения (с текущей версией PostgreSQL) с использованием протокола «расширенного запроса» и «безымянного оператора» и выполнение некоторых других вещей (укажите некоторые параметры во время сообщения «синтаксический анализ») )
- Играйте совершенно разными трюками, такими как драйвер JDBC.
Что делает Perl в настоящее время: я не знаю. Но упомянутая «красная сельдь» не очень вероятна.