Какая разница между cachePrepStmts и useServerPrepStmts в MySQL JDBC Driver

Драйвер JDBC MySQL определяет эти два свойства как:

  • useServerPrepStmts. Использовать подготовленные команды на стороне сервера, если сервер поддерживает их?

  • cachePrepStmts. Если драйвер кэширует этап синтаксического анализа PreparedStatements на подготовленных клиентских операциях, "проверка" для пригодность готовой и подготовленной серверной стороны сами заявления?

Является ли подготовленный оператор на стороне клиента способом повторного использования объектов PreparedStatements?

Если включен useServerPrepStmts, то, что точно кэшируется, поскольку MySQL не имеет кэш плана выполнения в любом случае?

Ответ 1

Во-первых, важно различать клиентские и серверные подготовленные операторы.

Подготовленные клиентом заявления

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

следующий код:

ps=conn.prepareStatement("select ?")
ps.setInt(1, 42)
ps.executeQuery()
ps.setInt(1, 43)
ps.executeQuery()

будет отображаться в журнале:

255 Query  select 42
255 Query  select 43

"Запрос" указывает, что на уровне протокола команда COM_QUERY отправляется с следующей строкой оператора.

Подготовленные отчеты сервера

Подготовленные сервером операторы являются "истинными" подготовленными операциями, означающими, что текст запроса отправляется на сервер, анализируется, а заполнитель и информация результата возвращается клиенту. Это вы получаете при настройке useServerPrepStmts=true. Строка оператора только один раз отправляется на сервер с вызовом COM_STMT_PREPARE (документировано здесь). Каждое выполнение выполняется путем отправки COM_STMT_EXECUTE с подготовленным дескриптором оператора и буквальными значениями для замены заполнителей.

В отличие от подготовленного клиента, мы можем использовать аналогичный блок кода (но на этот раз с включенными подготовленными операциями):

ps2=conn2.prepareStatement("select ?")
ps2.setInt(1, 42)
ps2.executeQuery()
ps2.setInt(1, 43)
ps2.executeQuery()

И журнал покажет:

254 Prepare    select ?
254 Execute    select 42
254 Execute    select 43

Вы можете видеть, что оператор готов к выполнению. Журнал делает нам одолжение и показывает полную инструкцию для выполнения, но на самом деле для каждого исполнения отправляются только значения заполнителя от клиента к серверу.

Кэширование подготовленных заявлений

Многие пулы подключений будут кэшировать подготовленные инструкции через использование соединения, что означает, что если вы вызываете conn.prepareStatement("select ?"), он будет возвращать тот же экземпляр PreparedStatement при последовательных вызовах с той же строкой оператора. Это полезно, чтобы избежать повторной подготовки той же строки на сервере, когда соединения возвращаются в пул между транзакциями.

Параметр MySQL JDBC cachePrepStmts будет кэшировать подготовленные операторы таким образом (как подготовленные как клиентские, так и серверные операторы), а также кэшировать "готовность" к заявлению. В MySQL есть некоторые утверждения, которые не подготавливаются на стороне сервера. Драйвер попытается подготовить отчет на сервере, если он считает, что это возможно, и, если подготовка не удалась, вернитесь к подготовленному клиентом оператору. Эта проверка является дорогостоящей из-за необходимости совершить кругосветное путешествие на сервер. Опция также кэширует результат этой проверки.

Надеюсь, что это поможет.