缓存 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。注释掉上面的配置行并重新启动以关闭查询日志记录。