我正在努力加快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。注释掉上面的配置行,然后重新启动以关闭查询日志记录。