2017-01-14 13 views
2

Я пытаюсь ускорить «SELECT * FROM WHERE name =?» вид запросов в Play! + Приложение Scala. Я использую Play 2.4 + Scala 2.11 + play-slick-1.1.1. Этот пакет использует версию Slick-3.1.Cache Slick Действия DBIO

Моя гипотеза заключалась в том, что пятно генерирует подготовленные утверждения из действий DBIO, и они выполняются. Поэтому я попытался их кэшировать, покупая включение флага cachePrepStmts = true Однако я все еще вижу сообщения «Подготовка заявления ...» в журнале, что означает, что PS не кэшируется! Как следует инструктировать slick для их кеширования?

Если я запустил следующий код, не следует ли кэшировать PS в какой-то момент?

for (i <- 1 until 100) { 
    Await.result(db.run(doctorsTable.filter(_.userName === name).result), 10 seconds) 
} 

Slick конфигурации выглядит следующим образом:

slick.dbs.default { 
    driver="slick.driver.MySQLDriver$" 
    db { 
    driver="com.mysql.jdbc.Driver" 

    url="jdbc:mysql://localhost:3306/staging_db?useSSL=false&cachePrepStmts=true" 

    user = "user" 

    password = "passwd" 

    numThreads = 1 // For not just one thread in HikariCP 

    properties = { 
     cachePrepStmts = true 
     prepStmtCacheSize = 250 
     prepStmtCacheSqlLimit = 2048 
    } 
    } 

} 

Update 1

Я попытался следующие согласно предложению @ Pawel о используя скомпилированных запросов:

val compiledQuery = Compiled { name: Rep[String] => 
    doctorsTable.filter(_.userName === name) 
} 


val stTime = TimeUtil.getUtcTime 
for (i <- 1 until 100) { 
    FutureUtils.blockFuture(db.compiledQuery(name).result), 10) 
} 
val endTime = TimeUtil.getUtcTime - stTime 
Logger.info(s"Time Taken HERE $endTime") 

В моей logs Я все еще вижу оператор вроде:

2017-01-16 21:34:00,510 DEBUG [db-1] s.j.J.statement [?:?] Preparing statement: select ... 

Также сроки этого также остаются неизменными. Каков желаемый результат? Должен ли я больше не видеть эти заявления? Как я могу проверить, действительно ли подготовленные заявления действительно используются повторно.

ответ

1

Для MySQL необходимо установить дополнительный JDBC флаг, useServerPrepStmts=true

HikariCP в MySQL configuration page ссылки на весьма полезный документ, который обеспечивает некоторые простые performance tuning варианты конфигурации для MySQL JDBC.

Вот некоторые из найденных мне полезных (вам нужно, чтобы & присоединить их к URL-адресу jdbc для опций, не отображаемых API-интерфейсом Hikari). Обязательно прочитайте связанный документ и/или документацию MySQL для каждой опции; должен быть в основном надежный в использовании.

zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8 
rewriteBatchedStatements=true 
maintainTimeStats=false 
cacheServerConfiguration=true 
avoidCheckOnDuplicateKeyUpdateInSQL=true 
dontTrackOpenResources=true 
useLocalSessionState=true 
cachePrepStmts=true 
useServerPrepStmts=true 
prepStmtCacheSize=500 
prepStmtCacheSqlLimit=2048 

Также обратите внимание, что инструкции кэшируются в потоке; в зависимости от того, что вы установили для соединения Hikari maxLifetime и какой нагрузки на сервер, использование памяти будет соответственно увеличиваться как на сервере, так и на клиенте (например, если вы установите максимальное время подключения для подключения к MySQL по умолчанию 8 часов, сервер и клиент будут поддерживать N подготовленный заявления, живые в памяти для жизни каждого соединения).

p.s.Любопытно, если узкое место действительно является кэшированием высказываний или что-то конкретное для Slick.

EDIT

войти заявления включить журнал запросов. В MySQL 5.7 вы бы добавить к вашему my.cnf:

general-log=1 
general-log-file=/var/log/mysqlgeneral.log 

, а затем sudo touch /var/log/mysqlgeneral.log с последующим перезапуском туздЫ. Прокомментируйте выше строки конфигурации и перезапустите, чтобы отключить ведение журнала запросов.

+0

Спасибо за ваш ответ. На данный момент мне очень любопытно, работает ли кэширование в целом или нет в компиляции Slick + Hikari. Я просто задаюсь вопросом в JDBC, как я могу проверить, кэшировано ли готовое состояние или нет? – Richeek

+0

с кешированием на стороне сервера, включенным в журнал запросов mysql, будет показан один готовый + выполнить для первоначального запроса, а затем выполняется только для всех последующих попыток кэша для целевого оператора. Если вы добавите 'useServerPrepStmts = true', вы должны увидеть этот шаблон в журнале. – virtualeyes

+0

Я пробовал это. На самом деле вы знаете, как включить ведение журнала запросов mysql? Я включил slick logging и всегда показывает, что «Подготовка оператора: select ...» - это тип журналов, независимо от того, что. Это утверждение происходит от JdbcBackend.scala: https://github.com/slick/slick/blob/074002eb6290c0742ab28135c8109b3465311b81/slick/src/main/scala/slick/jdbc/JdbcBackend.scala#L301, что создает путаницу – Richeek

2

Вам необходимо использовать Compiled запросов, которые точно выполняют то, что вы хотите.

Просто измените выше кода:

val compiledQuery = Compiled { name: Rep[String] => 
    doctorsTable.filter(_.userName === name) 
} 

for (i <- 1 until 100) { 
    Await.result(db.run(compiledQuery(name).result), 10 seconds) 
} 

Я извлек выше name в качестве параметра (потому что вы, как правило, требуется изменить некоторые параметры в своих PreparedStatement с), но это, безусловно, необязательная часть.

Для получения дополнительной информации Вы можете обратиться к: http://slick.lightbend.com/doc/3.1.0/queries.html#compiled-queries

+0

Aha! Позвольте мне проверить это и вернуться к вам. Спасибо за это очень полезное замечание :) Кстати, у вас есть какие-либо комментарии к моей пятнистой конфигурации? Считаете ли вы, что объект 'properties' является избыточным, поскольку я указываю URL-адрес JDBC? – Richeek

+0

Я не уверен, что его работа! Я сделал время этого цикла с и без скомпилированного запроса, и он выходит почти так же. Я вижу 'Готовый оператор: выберите user_name, ...' сообщения, поступающие из этого файла: https://github.com/slick/slick/blob/074002eb6290c0742ab28135c8109b3465311b81/slick/src/main/scala/slick/jdbc/JdbcBackend.scala как я могу убедиться, что подготовленные заявления действительно используются повторно? – Richeek

+0

Вы уверены, что у вас есть 'val compiledQuery', а не' def compiledQuery'? –