使用“pull”(datahike)检索 400 个实体的属性的慢速查询

Slow query using `pull` (datahike) to retrieve attributes on 400 entities

提问人:silian-rail 提问时间:10/31/2023 最后编辑:silian-rail 更新时间:11/6/2023 访问量:80

问:

我在 JVM 上使用 Datahike 0.6.1531(不是 Datomic)。我有一个要在 Web 应用程序中显示的书名列表。如果这本书是“值得注意的”,我会做一些特别的事情,比如应用背景色或附加表情符号。

我想返回一个类似于以下内容的向量:

[{:db/id 339, :resource-name "Notation as a Tool of Thought"}
 {:db/id 338, :resource-name "The Science of Radio", :notable? :true}
 {:db/id 337, :resource-name "Journey Into Mathematics"}
 {:db/id 336, :resource-name "Street Fighting Mathematics"}
 ...]

在 400 个左右的实体范围内使用 3 个 attr-id(包括 )执行以下查询需要 ~2,900 毫秒:pull-many:db/id

(require '[datahike.api :as d]) ; version 0.6.1531
(d/pull-many @conn [:db/id :resource-name :notable?] 
  (range 1 400))

查询时间慢是 EAV 数据库的固有权衡,还是我未能以某种非常明显的方式进行优化?

Clojure Datomic

评论

2赞 claj 10/31/2023
您可能应该澄清您正在使用 DataHike,但也要描述您正在使用的 Clojure 运行时环境。它是在 SPA 中还是在基于 JVM 的后端应用程序中进行?
0赞 silian-rail 11/1/2023
是的,我想添加标签,但没有声誉来这样做。datahike
0赞 silian-rail 11/1/2023
Clojure (1.10.0) JVM
0赞 silian-rail 11/6/2023
此问题已由 Datahike 维护人员解决/解决 github.com/replikativ/datahike/pull/653

答:

0赞 claj 10/31/2023 #1

这个问题最初出现在 Clojurians slack 的 DataHike 频道中,所以我从那里将我的答案编辑成一个更长的单篇文章答案。DataHike 是 Clojure/ClojureScript 中 Datalog 查询引擎的众多实现之一。

由于您使用的是普通的 JVM Clojure(它往往是性能最高的),因此我希望得到更快的结果。我从 Datomic 获得的经验是,这样的查询应该快很多倍。

DataScript(这是 DataHike 最初基于的数据日志实现)有时可能有点慢,但对于 clojure/script 环境来说,结果似乎有点太慢了。

DataScript 中 pull-api 的实现与 DataHike 中 pull-api 的实现是完全不同的,其中 DataHike 似乎比 DataScript 做了更多的簿记和检查(这使得 DataHike 慢得多,但也更容易让它正常工作)。

JIT/更好的性能指标

您的查询最多包含数据库中的 400 个实体。这可能很少有人触发 JIT 重新编译/优化(这就是在长时间运行的生产代码中使这一切更快的原因)。像 Criterium (clojure) 或 Tufte (Criterium 的 ClojureScript 移植)这样的工具将运行大量测试,以确保 JVM 或 JavaScript VM 是“热的”,大多数 JIT 优化已经到位。

我建议您使用 Criterium 或 Tufte 测试性能。

DataHike 仍然更具实验性(但可用),并且与 DataScript 具有不同的范围,这可能会使查询引擎慢得多,但它应该不会这么慢(恕我直言)。

0赞 silian-rail 11/6/2023 #2

Datahike 维护者在此拉取请求中解决并解决了此问题: https://github.com/replikativ/datahike/pull/653