Значительно другое время выполнения запроса в приложении - PullRequest
2 голосов
/ 02 февраля 2012

У меня проблема с масштабированием приложения, использующего бэкэнд PostgreSQL 9. У меня есть одна таблица, размер которой составляет около 40 миллионов записей и растет, и условные запросы к ней значительно замедлились.

Чтобы выяснить, что происходит не так, я сделал снимок базы данных при разработке и поместил в журнал запросы со временем выполнения.

Теперь о запутанной части и сути вопроса ...

Время выполнения моих запросов в журнале значительно отличается (на порядок +) от времени, которое я получаю при выполнении «точно такого же» запроса в DbVisualizer, чтобы получить план объяснения.

Я говорю «точно», но на самом деле разница в том, что приложение использует подготовленный оператор , к которому я привязываю значения во время выполнения, в то время как запросы, которые я выполняю в DbVisualizer, уже имеют эти значения. Сами значения точно такие, как я их вытащил из журнала.

Может ли использование подготовленных утверждений иметь такое большое значение?

Ответы [ 2 ]

3 голосов
/ 03 февраля 2012

Эрвин прибивает это, но позвольте мне добавить, что расширенный протокол запросов позволяет вам использовать больше вариантов готовых операторов.Помимо избежания повторного разбора и перепланирования, одним большим преимуществом подготовленных операторов является отдельная отправка значений параметров, что позволяет избежать экранирования и анализа накладных расходов, не говоря уже о возможности SQL-инъекций и ошибок, если вы не используете API, который обрабатываетпараметры таким образом, что вы не можете забыть избежать их.

http://www.postgresql.org/docs/9.1/static/protocol-flow.html

Планирование запроса для именованных объектов подготовленного оператора происходит при обработке сообщения Parse.Если запрос будет неоднократно выполняться с различными параметрами, может быть полезно отправить одно сообщение Parse, содержащее параметризованный запрос, за которым следуют несколько сообщений Bind и Execute.Это позволит избежать повторного планирования запроса при каждом выполнении.

Неименованный подготовленный оператор также планируется во время обработки анализа, если сообщение Parse не определяет параметры.Но если есть параметры, планирование запросов происходит каждый раз, когда предоставляются параметры Bind.Это позволяет планировщику использовать фактические значения параметров, предоставляемых каждым сообщением Bind, а не использовать общие оценки.

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

Если вы используете PHP с PDO, обратите внимание, что реализация подготовленного оператора PDO довольно бесполезна для postgres, поскольку она использует именованные подготовленные операторы, ноповторная подготовка каждый раз, когда вы вызываете метод prepare (), кэширование плана не выполняется.Таким образом, вы получаете худшее из обоих: много поездок туда и обратно и план без параметров.Я видел, что это в 1000 раз медленнее, чем pg_query () и pg_query_params () в определенных запросах, где оптимизатору postgres действительно нужно знать параметры, чтобы получить оптимальный план.pg_query использует необработанные запросы, pg_query_params использует безымянные подготовленные операторы.Обычно один быстрее другого, это зависит от размера данных параметра.

3 голосов
/ 02 февраля 2012

Ответ ДА . Подготовленные заявления сокращаются в обе стороны.

С одной стороны, запрос не нужно перепланировать для каждого выполнения, что экономит некоторые накладные расходы. Это может иметь значение или быть едва заметным, в зависимости от сложности запроса.

С другой стороны, при неравномерном распределении данных план запроса с единым размером для всех может оказаться плохим выбором. Вызывается с определенными значениями, другой план запроса может быть (намного) более подходящим.

Выполнение запроса со значениями параметров на месте может привести к другому плану запроса. Больше затрат на планирование, возможно (намного) лучший план запросов.

Также рассмотрим безымянные подготовленные заявления , например, @ peufeu при условии . Они перепланируют запрос с учетом параметров каждый раз, и у вас все еще есть безопасная обработка параметров.

Аналогичные соображения применимы к запросам внутри функций PL / pgSQL, где запросы могут обрабатываться как подготовленные операторы внутри системы - если только они не выполняются динамически с EXECUTE. Я цитирую руководство по Выполнение динамических команд :

Важным отличием является то, что EXECUTE будет перепланировать команду на каждое выполнение, генерация плана, который является специфическим для текущего значения параметров; тогда как PL / pgSQL в противном случае может создать общий план и кешировать его для повторного использования. В ситуациях, когда лучший план зависит строго по значениям параметров, может быть полезно использовать EXECUTE для положительно убедитесь, что общий план не выбран.

Кроме того, применяются общие рекомендации по оптимизации производительности .

...