缓存Slick DBIO操作



我正在努力加快Play中"SELECT*FROM WHERE name=?"类型的查询!+Scala应用程序。我使用的是Play 2.4+Scala 2.11+Play-slick-1.1.1软件包。此软件包使用Slick-3.1版本。

我的假设是,slick从DBIO操作中生成Prepared语句,然后执行这些语句。所以我试着缓存它们,打开flagcachePrepStmts=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
}
}
}

更新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语句是否确实被重用。

您需要使用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-查询

对于MySQL,您需要设置一个额外的jdbc标志useServerPrepStmts=true

HikariCP的MySQL配置页面链接到一个非常有用的文档,该文档为MySQL jdbc提供了一些简单的性能调优配置选项。

以下是我发现有用的一些(对于Hikari的API没有公开的选项,您需要&将它们附加到jdbc url)。请务必阅读每个选项的链接文档和/或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

然后CCD_ 8,然后重新启动mysqld。注释掉上面的配置行,然后重新启动以关闭查询日志记录。

最新更新