缓存光滑的DBIO操作

时间:2017-01-14 10:10:55

标签: scala playframework slick hikaricp play-slick

我正在努力加快“SELECT * FROM WHERE name =?” Play中的一些查询! + Scala app。我正在使用Play 2.4 + Scala 2.11 + play-slick-1.1.1包。该软件包使用Slick-3.1版本。

我的假设是,slick会从DBIO操作生成Prepared语句并执行它们。所以我尝试缓存它们买入开启标志 cachePrepStmts = true 但是我仍然在日志中看到“正在准备语句...”消息,这意味着PS没有被缓存!应该如何指示光滑缓存它们?

如果我运行以下代码,不应该在某个时候缓存PS吗?

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

Slick config如下:

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

HikariCP的MySQL configuration page链接到一个非常有用的文档,它为MySQL jdbc提供了一些简单的performance tuning配置选项。

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

修改

到log语句启用查询日志。在MySQL 5.7上,您将添加到my.cnf

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

然后sudo touch /var/log/mysqlgeneral.log然后重启mysqld。注释掉上面的配置行并重新启动以关闭查询记录。