缓存 Slick DBIO 操作
Cache Slick DBIO Actions
我正尝试在 Play 中加快 "SELECT * FROM WHERE name=?" 类查询的速度! + 斯卡拉应用程序。我正在使用 Play 2.4 + Scala 2.11 + play-slick-1.1.1 包。此包使用Slick-3.1版本。
我的假设是 slick 从 DBIO 操作生成准备好的语句并执行它们。所以我尝试缓存它们购买打开标志 cachePrepStmts=true
但是我仍然在日志中看到 "Preparing statement..." 消息,这意味着 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
}
}
}
更新 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")
在我的日志中,我仍然看到如下语句:
2017-01-16 21:34:00,510 DEBUG [db-1] s.j.J.statement [?:?] Preparing statement: select ...
此外,此时间安排也保持不变。期望的输出是什么?我不应该再看到这些陈述吗?如何验证是否确实重用了 Prepared statements。
您需要使用 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
对于MySQL你需要设置一个额外的jdbc标志,useServerPrepStmts=true
HikariCP 的 MySQL configuration page links to a quite useful document that provides some simple performance tuning 配置选项 MySQL jdbc。
这里有一些我觉得有用的(对于 Hikari 的 API 未公开的选项,您需要 &
将它们附加到 jdbc url ).请务必阅读每个选项的链接文档 and/or 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 的东西。
编辑
to log 语句启用查询日志。在 MySQL 5.7 上,您将添加到 my.cnf
:
general-log=1
general-log-file=/var/log/mysqlgeneral.log
然后是 sudo touch /var/log/mysqlgeneral.log
然后重新启动 mysqld。注释掉上面的配置行并重新启动以关闭查询日志记录。
我正尝试在 Play 中加快 "SELECT * FROM WHERE name=?" 类查询的速度! + 斯卡拉应用程序。我正在使用 Play 2.4 + Scala 2.11 + play-slick-1.1.1 包。此包使用Slick-3.1版本。
我的假设是 slick 从 DBIO 操作生成准备好的语句并执行它们。所以我尝试缓存它们购买打开标志 cachePrepStmts=true 但是我仍然在日志中看到 "Preparing statement..." 消息,这意味着 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
}
}
}
更新 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")
在我的日志中,我仍然看到如下语句:
2017-01-16 21:34:00,510 DEBUG [db-1] s.j.J.statement [?:?] Preparing statement: select ...
此外,此时间安排也保持不变。期望的输出是什么?我不应该再看到这些陈述吗?如何验证是否确实重用了 Prepared statements。
您需要使用 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
对于MySQL你需要设置一个额外的jdbc标志,useServerPrepStmts=true
HikariCP 的 MySQL configuration page links to a quite useful document that provides some simple performance tuning 配置选项 MySQL jdbc。
这里有一些我觉得有用的(对于 Hikari 的 API 未公开的选项,您需要 &
将它们附加到 jdbc url ).请务必阅读每个选项的链接文档 and/or 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 的东西。
编辑
to log 语句启用查询日志。在 MySQL 5.7 上,您将添加到 my.cnf
:
general-log=1
general-log-file=/var/log/mysqlgeneral.log
然后是 sudo touch /var/log/mysqlgeneral.log
然后重新启动 mysqld。注释掉上面的配置行并重新启动以关闭查询日志记录。