Подготовленные материалы и производительность

Поэтому я продолжаю слышать, что PreparedStatements хороши для производительности.

У нас есть приложение Java, в котором мы используем регулярное «Statement» больше, чем мы используем «PreparedStatement». При попытке перейти к использованию более PreparedStatements, я пытаюсь получить более полное представление о том, как работают PreparedStatements – на стороне клиента и на стороне сервера.

Итак, если у нас есть некоторые типичные операции CRUD и многократно обновлять объект в приложении, помогает ли это использовать PS? Я понимаю, что нам придется закрывать PS каждый раз, иначе это приведет к утечке курсора.

Итак, как это помогает в производительности? Является ли драйвер кэшем предварительно скомпилированный оператор и дает мне копию при следующем подключении connection.prepareStatement? Или сервер БД помогает?

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

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

// some code blah blah update(); // some more code blah blah update(); .... public void update () throws SQLException{ try{ PreparedStatement ps = connection.prepareStatement("some sql"); ps.setString(1, "foobar1"); ps.setString(2, "foobar2"); ps.execute(); }finally { ps.close(); } } 

Невозможно на самом деле повторно использовать java-объект ps, и я понимаю, что фактический вызов connection.prepareStatement довольно дорог.

Это и привело меня к первоначальному вопросу. Это «некоторые sql» PreparedStatement все еще кэшируются и повторно используются под обложками, о которых я не знаю?

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

Заранее спасибо.

Подготовленные заявления могут повысить производительность при повторном использовании того же заявления, которое вы подготовили:

 PreparedStatement ps = connection.prepare("SOME SQL"); for (Data data : dataList) { ps.setInt(1, data.getId()); ps.setString(2, data.getValue(); ps.executeUpdate(); } ps.close(); 

Это намного быстрее, чем создание инструкции в цикле.

Некоторые платформы также кэшируют подготовленные заявления, так что даже если вы их закроете, они могут быть восстановлены быстрее.

Однако, даже если производительность была идентичной, вы все равно должны использовать подготовленные инструкции для предотвращения SQL-инъекций. В моей компании это вопрос интервью; сделайте это неправильно, и мы не можем нанять вас.

Понятие, что подготовленные заявления в первую очередь о производительности, является чем-то неправильным, хотя это довольно распространенный вопрос.

Другой плакат отметил, что он отметил улучшение скорости около 20% в Oracle и SQL Server. Я отметил аналогичную цифру с MySQL. Оказывается, что parsing запроса просто не является такой значительной частью работы. В очень загруженной системе баз данных также неясно, что синтаксический анализ запросов повлияет на общую пропускную способность: в целом, вероятно, просто будет использовать процессорное время, которое в противном случае было бы бездействующим, когда данные возвращались с диска.

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

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

Более подробную информацию можно найти здесь:

http://www.theserverside.com/tt/articles/article.tss?l=Prepared-Statments

и вы можете захотеть взглянуть на Spring JDBCTemplate в качестве альтернативы прямому использованию JDBC.

http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html

Разбор SQL – это не единственное, что происходит. Там проверяется, что таблицы и столбцы действительно существуют, создавая план запроса и т. Д. Вы платите это один раз с помощью PreparedStatement.

Действительно, привязка для защиты от SQL-инъекций – очень хорошая вещь. Недостаточно, ИМО. Вы все равно должны проверять ввод до перехода на уровень сохранения.

Итак, как это помогает в производительности? Является ли драйвер кэшем предварительно скомпилированный оператор и дает мне копию при следующем подключении connection.prepareStatement? Или сервер БД помогает?

Я отвечу с точки зрения производительности. Другие здесь уже заявили, что PreparedStatement s устойчивы к SQL-инъекции (благословенное преимущество).

Приложение (Драйвер JDBC) создает PreparedStatement и передает его в СУБД с помощью заполнителей ( ? ). СУРБД прекомпилирует, применяя оптимизацию запроса (при необходимости) полученного PreparedStatement и (в некоторых), как правило, кэширует их. Во время выполнения PreparedStatement используется предварительно скомпилированное PreparedStatement , заменяя каждый заполнитель соответствующими значениями и рассчитывается. Это контрастирует с Statement который компилирует его и выполняет его напрямую, PreparedStatement компилирует и оптимизирует запрос только один раз . Теперь этот сценарий, описанный выше, не является абсолютным случаем для всех поставщиков JDBC, но по сути, это то, как PreparedStatement используется и работает.

Анекдотически. Несколько лет назад я провел несколько экспериментов с подготовленными и динамическими операторами, использующими ODBC в Java 1.4, с Oracle и SQL Server. Я обнаружил, что подготовленные заявления могут быть на 20% быстрее для определенных запросов, но существуют различия в отношении поставщиков, в отношении которых запросы были улучшены в какой степени. (На самом деле это не удивительно.)

Суть в том, что если вы будете повторно использовать один и тот же запрос повторно, подготовленные операторы могут помочь повысить производительность; но если ваша производительность настолько плоха, что вам нужно что-то сделать с этим немедленно, не рассчитывайте на использование подготовленных заявлений, чтобы дать вам радикальный импульс. (20% обычно нечего писать домой.)

Конечно, ваш пробег может варьироваться.

Это и привело меня к первоначальному вопросу. Это «некоторые sql» PreparedStatement все еще кэшируются и повторно используются под обложками, о которых я не знаю?

Да, по крайней мере, с Oracle. В базе данных Oracle® Database JDBC Руководство разработчика Неявное кэширование выписки (выделено мной)

Когда вы включаете неявное кэширование Statement, JDBC автоматически кэширует подготовленный или вызываемый оператор, когда вы вызываете метод close этого объекта-оператора. Готовые и вызываемые операторы кэшируются и извлекаются с использованием стандартных объектов объекта соединения и методов объекта-оператора.

Обычные заявления неявно кэшируются, потому что неявное кэширование Statement использует строку SQL в качестве ключа, а простые инструкции создаются без строки SQL. Следовательно, неявное кэширование Statement применяется только к OraclePreparedStatement и OracleCallableStatement , которые создаются с помощью строки SQL. Вы не можете использовать неявное кэширование Statement с OracleStatement. Когда вы создаете OraclePreparedStatement или OracleCallableStatement , драйвер JDBC автоматически ищет кеш для соответствующего оператора .

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

В качестве примера, с точки зрения производительности базы данных, firebase database Oracle кэширует план выполнения некоторых запросов после каждого вычисления (это неверно для всех версий и всей конфигурации Oracle). Вы можете найти улучшения, даже если закрыть заявление и открыть новый, потому что это делается на уровне РСУБД. Этот тип кэширования активируется только в том случае, если два последующих запроса (char-by-char) одинаковы. Это не относится к нормальным операторам, поскольку параметры являются частью запроса и производят разные строки SQL.

Некоторые другие СУБД могут быть более «интеллектуальными», но я не ожидаю, что они будут использовать сложные алгоритмы сопоставления образцов для кэширования планов выполнения, поскольку это приведет к снижению производительности. Вы можете утверждать, что вычисление плана выполнения является лишь небольшой частью выполнения запроса. В общем случае я согласен, но … это зависит. Имейте в виду, что, как правило, вычисление плана выполнения может быть дорогостоящей задачей, потому что rdbms необходимо проконсультироваться с данными вне памяти, такими как статистика (а не только Oracle).

Однако аргумент о кешировании варьируется от планов исполнения до других частей процесса извлечения. Предоставление RDBMS в несколько раз того же запроса (без углубления для конкретной реализации) помогает идентифицировать уже вычисленные структуры на уровне JDBC (драйвера) или RDBMS. Если вы не найдете каких-либо особых преимуществ в производительности сейчас, вы не можете исключить, что повышение производительности будет реализовано в будущих / альтернативных версиях драйвера / rdbms.

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

1. PreparedStatement позволяет писать динамический и параметрический запрос

Используя PreparedStatement в Java, вы можете писать параметризованные sql-запросы и отправлять разные параметры с помощью тех же запросов sql, которые намного лучше, чем создание разных запросов.

2. PreparedStatement быстрее, чем Statement в Java

Одним из основных преимуществ использования PreparedStatement является повышение производительности. PreparedStatement получает предварительную компиляцию. В базе данных и в ней также кэшируется план доступа, который позволяет базе данных выполнять параметрический запрос, написанный с использованием подготовленного оператора, намного быстрее, чем обычный запрос, потому что у него меньше работы. Вы всегда должны пытаться использовать PreparedStatement в коде JDBC для уменьшения нагрузки на базу данных. Чтобы получить выгоду от производительности, стоит отметить, что она использует только параметризованную версию SQL-запроса, а не конкатенацию строк

3. PreparedStatement предотвращает атаки SQL Injection в Java

Подробнее: http://javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-java-jdbc.html#ixzz3LejuMnVL

Короткий ответ:

PreparedStatement помогает повысить производительность, поскольку обычно клиенты БД выполняют один и тот же запрос повторно, и это позволяет сделать некоторую предварительную обработку исходного запроса для ускорения следующих повторяющихся запросов .

Длительный ответ:

Согласно Википедии , типичный рабочий процесс использования подготовленного оператора выглядит следующим образом:

Подготовьте : шаблон заявления создается приложением и отправляется в систему управления базами данных (СУБД). Определенные значения остаются неопределенными, называемыми параметрами, заполнителями или связующими переменными (помечены как «?» Ниже): ВСТАВИТЬ В ПРОДУКТ (имя, цена) ЦЕННОСТИ (?,?)

(Предварительная компиляция) : СУБД анализирует, компилирует и выполняет оптимизацию запросов в шаблоне оператора и сохраняет результат без его выполнения.

Выполнение : позднее приложение прикладывает (или связывает) значения для параметров, а СУБД выполняет оператор (возможно, возвращает результат). Приложение может выполнять оператор столько раз, сколько требуется с разными значениями. В этом примере он может поставить «Хлеб» для первого параметра и «1.00» для второго параметра.

Подготовить:

В JDBC шаг «Подготовить» выполняется путем вызова java.sql.Connection. API-интерфейс prepareStatement (String sql). Согласно его Джавадоку:

Этот метод оптимизирован для обработки параметрических операторов SQL, которые извлекают выгоду из предварительной компиляции. Если драйвер поддерживает предварительную компиляцию, метод prepareStatement отправит инструкцию в базу данных для предварительной компиляции. Некоторые драйверы могут не поддерживать предварительную компиляцию. В этом случае оператор не может быть отправлен в базу данных до тех пор, пока не будет выполнен объект PreparedStatement. Это не оказывает прямого влияния на пользователей; однако это влияет на то, какие методы бросают определенные объекты SQLException.

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

Прекомпиляция:

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

Выполнение:

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

Вывод:

С точки зрения производительности, использование инструкции подготовки является двухфазным процессом:

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

И если вы хотите узнать более подробную информацию, есть некоторые статьи, объясняющие преимущества PrepareStatement:

  1. http://javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-java-jdbc.html
  2. http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html
  • Выполнение стресс-теста в веб-приложении?
  • Делают ли c ++ шаблоны медленными?
  • Как перегружать std :: swap ()
  • Как ускорить алгоритм A * при больших пространственных масштабах?
  • boolean против BitSet: что более эффективно?
  • Структура агрегации Mongodb: используется ли индекс использования группы?
  • Относительная производительность команды x86 inc vs. add
  • Встроенная функция v. Макрос в C - Что такое служебные данные (память / скорость)?
  • Является ли тернарный оператор быстрее, чем условие «если»
  • Самый быстрый способ удалить все непечатаемые символы из строки Java
  • Есть ли 128-битное целое число в C ++?
  • Давайте будем гением компьютера.