Slick 中的典型表现(ver. 3.1.1)
Typical performance in Slick (ver. 3.1.1)
我有以下 SQL 查询:
select `sr_roleName`, `sr_id` from `db_security_role` where `sr_roleName` = 'admin'
它是从以下 Slick 代码生成的:
RoleTable.filter(_.name === roleName).result.head
所以 - 它看起来很简单(实际上是您可能拥有的最简单的东西,对吧?)。现在让我们看看以下结果(下面的日志):
[debug] s.c.QueryCompilerBenchmark - ------------------- Phase: Time ---------
[debug] s.c.QueryCompilerBenchmark - assignUniqueSymbols: 0.257579 ms
[debug] s.c.QueryCompilerBenchmark - inferTypes: 0.774230 ms
[debug] s.c.QueryCompilerBenchmark - expandTables: 18.949290 ms
[debug] s.c.QueryCompilerBenchmark - forceOuterBinds: 3.438698 ms
[debug] s.c.QueryCompilerBenchmark - removeMappedTypes: 2.760705 ms
[debug] s.c.QueryCompilerBenchmark - expandSums: 0.702326 ms
[debug] s.c.QueryCompilerBenchmark - emulateOuterJoins: 1.025963 ms
[debug] s.c.QueryCompilerBenchmark - expandRecords: 1.022323 ms
[debug] s.c.QueryCompilerBenchmark - flattenProjections: 10.691557 ms
[debug] s.c.QueryCompilerBenchmark - rewriteJoins: 0.790561 ms
[debug] s.c.QueryCompilerBenchmark - verifySymbols: 4.421257 ms
[debug] s.c.QueryCompilerBenchmark - relabelUnions: 1.511849 ms
[debug] s.c.QueryCompilerBenchmark - createAggregates: 0.612787 ms
[debug] s.c.QueryCompilerBenchmark - resolveZipJoins: 0.723972 ms
[debug] s.c.QueryCompilerBenchmark - pruneProjections: 4.261886 ms
[debug] s.c.QueryCompilerBenchmark - rewriteDistinct: 2.408857 ms
[debug] s.c.QueryCompilerBenchmark - createResultSetMapping: 2.745822 ms
[debug] s.c.QueryCompilerBenchmark - hoistClientOps: 7.755399 ms
[debug] s.c.QueryCompilerBenchmark - reorderOperations: 1.650360 ms
[debug] s.c.QueryCompilerBenchmark - mergeToComprehensions: 27.408578 ms
[debug] s.c.QueryCompilerBenchmark - optimizeScalar: 1.784032 ms
[debug] s.c.QueryCompilerBenchmark - removeFieldNames: 13.811206 ms
[debug] s.c.QueryCompilerBenchmark - codeGen: 20.328294 ms
[debug] s.c.QueryCompilerBenchmark - TOTAL: 129.837531 ms
[debug] s.j.J.statement - Preparing statement: select `sr_roleName`, `sr_id` from `db_security_role` where `sr_roleName` = 'admin'
[debug] s.j.J.benchmark - Execution of prepared statement took 425µs
如您所见,实际查询执行成本(耗时)约为 425µs。可能 - 它在本地机器/本地数据库上执行。然而对我来说极其奇怪的是:整个查询准备时间总共花费了 129.837531 毫秒(这是实际查询执行时间的 300 倍)。
基本上我的问题是:
这是Slick的典型性能特征吗?
有什么明显的地方我可能做错了吗?
谢谢
好像有道理。每次执行参数化查询时,slick 都需要重新编译它。这可以通过预编译此类查询来避免。例如:
def findByRoleName(roleName: Rep[String]) = RoleTable.filter(_.name === roleName)
val findByRoleNameCompiled = Compiled(findByRoleName _)
val result = findByRoleNameCompiled("myRole").result.head
现在查询将只编译一次,您应该会注意到性能有所提高。这也适用于插入、更新和删除。有关详细信息,请参阅文档中的 Compiled Queries。
实际上正确答案在@szeiger 的评论中:
查询准备时间长只是由于 JVM 未预热造成的。多次执行各种查询后,下一个查询准备得更快。还值得记住@Roman 指出的查询编译(尽管这并不是问题本质的全部内容)。
@szeiger 在上述评论中的引用基本上是对这个问题的最佳答案:
Averaged over 53 queries of low to medium complexity, I get 183 ms for the first run and only 14 ms after a few dozen runs
我有以下 SQL 查询:
select `sr_roleName`, `sr_id` from `db_security_role` where `sr_roleName` = 'admin'
它是从以下 Slick 代码生成的:
RoleTable.filter(_.name === roleName).result.head
所以 - 它看起来很简单(实际上是您可能拥有的最简单的东西,对吧?)。现在让我们看看以下结果(下面的日志):
[debug] s.c.QueryCompilerBenchmark - ------------------- Phase: Time ---------
[debug] s.c.QueryCompilerBenchmark - assignUniqueSymbols: 0.257579 ms
[debug] s.c.QueryCompilerBenchmark - inferTypes: 0.774230 ms
[debug] s.c.QueryCompilerBenchmark - expandTables: 18.949290 ms
[debug] s.c.QueryCompilerBenchmark - forceOuterBinds: 3.438698 ms
[debug] s.c.QueryCompilerBenchmark - removeMappedTypes: 2.760705 ms
[debug] s.c.QueryCompilerBenchmark - expandSums: 0.702326 ms
[debug] s.c.QueryCompilerBenchmark - emulateOuterJoins: 1.025963 ms
[debug] s.c.QueryCompilerBenchmark - expandRecords: 1.022323 ms
[debug] s.c.QueryCompilerBenchmark - flattenProjections: 10.691557 ms
[debug] s.c.QueryCompilerBenchmark - rewriteJoins: 0.790561 ms
[debug] s.c.QueryCompilerBenchmark - verifySymbols: 4.421257 ms
[debug] s.c.QueryCompilerBenchmark - relabelUnions: 1.511849 ms
[debug] s.c.QueryCompilerBenchmark - createAggregates: 0.612787 ms
[debug] s.c.QueryCompilerBenchmark - resolveZipJoins: 0.723972 ms
[debug] s.c.QueryCompilerBenchmark - pruneProjections: 4.261886 ms
[debug] s.c.QueryCompilerBenchmark - rewriteDistinct: 2.408857 ms
[debug] s.c.QueryCompilerBenchmark - createResultSetMapping: 2.745822 ms
[debug] s.c.QueryCompilerBenchmark - hoistClientOps: 7.755399 ms
[debug] s.c.QueryCompilerBenchmark - reorderOperations: 1.650360 ms
[debug] s.c.QueryCompilerBenchmark - mergeToComprehensions: 27.408578 ms
[debug] s.c.QueryCompilerBenchmark - optimizeScalar: 1.784032 ms
[debug] s.c.QueryCompilerBenchmark - removeFieldNames: 13.811206 ms
[debug] s.c.QueryCompilerBenchmark - codeGen: 20.328294 ms
[debug] s.c.QueryCompilerBenchmark - TOTAL: 129.837531 ms
[debug] s.j.J.statement - Preparing statement: select `sr_roleName`, `sr_id` from `db_security_role` where `sr_roleName` = 'admin'
[debug] s.j.J.benchmark - Execution of prepared statement took 425µs
如您所见,实际查询执行成本(耗时)约为 425µs。可能 - 它在本地机器/本地数据库上执行。然而对我来说极其奇怪的是:整个查询准备时间总共花费了 129.837531 毫秒(这是实际查询执行时间的 300 倍)。
基本上我的问题是:
这是Slick的典型性能特征吗?
有什么明显的地方我可能做错了吗?
谢谢
好像有道理。每次执行参数化查询时,slick 都需要重新编译它。这可以通过预编译此类查询来避免。例如:
def findByRoleName(roleName: Rep[String]) = RoleTable.filter(_.name === roleName)
val findByRoleNameCompiled = Compiled(findByRoleName _)
val result = findByRoleNameCompiled("myRole").result.head
现在查询将只编译一次,您应该会注意到性能有所提高。这也适用于插入、更新和删除。有关详细信息,请参阅文档中的 Compiled Queries。
实际上正确答案在@szeiger 的评论中:
查询准备时间长只是由于 JVM 未预热造成的。多次执行各种查询后,下一个查询准备得更快。还值得记住@Roman 指出的查询编译(尽管这并不是问题本质的全部内容)。
@szeiger 在上述评论中的引用基本上是对这个问题的最佳答案:
Averaged over 53 queries of low to medium complexity, I get 183 ms for the first run and only 14 ms after a few dozen runs