【问题标题】:What is an efficient way to access large-ish datasets using JDBC with Clojure使用 JDBC 和 Clojure 访问大型数据集的有效方法是什么
【发布时间】:2026-02-19 13:05:01
【问题描述】:

编辑

事实证明是 N00b 问题。我没有意识到运行lein ring server 会导致您的应用程序以解释模式运行,这就是它慢得多的原因。


可以优化以下 Clojure/JDBC 片段以使其运行(快得多)吗?
(defn test-sql []
  (sql/with-connection (db-connection)
    (sql/with-query-results results ["select * from users order by username asc"]
        (doseq [row results ] 
          (println "User" (row :first_name) (row :last_name)) results))))

我正在考虑将 Clojure 用于 ETL 项目。我写的第一个测试是从我有大约 28 万条记录的表中打印出数据。到目前为止,我提出的实现非常缓慢。在 Java 中大约需要 12 秒(即使使用 myBatis 填充对象而不是“原始”访问)使用我的 Clojure 解决方案需要大约 9.5 分钟。

我尝试使用 map 而不是 doseq,并尝试使用如下所示的光标:http://asymmetrical-view.com/2010/10/14/clojure-and-large-result-sets.html,但我得到的每个执行时间大致相同。

FWIW,执行 .println java.lang.System/out 时的结果相同(不足为奇),并使用 with-query-results*:

(defn test-sql2 []
  (sql/with-connection (db-connection)
    (sql/with-query-results* ["select * from users order by username asc"]
      (fn [row] (println "User" (row :first_name) (row :last_name))))))

一样,一样。

【问题讨论】:

  • 如果你只是用 Clojure 操作原始结果集,你会怎样?
  • @Bill 不确定您的想法。没有帮助,这是我使用 Clojure 的第一天 :-)
  • @Bill 我在我的答案中做了测试,奇怪的是时间更糟......背后似乎发生了某种魔法。起初我认为这是由于 JIT,我将 jdbc 复制到 jdbc2(源文件)并从 repl 中使用它,经过几次运行时间已经收敛。将ResultSet 传递给调用者会神奇地增加运行时间。

标签: jdbc clojure processing-efficiency


【解决方案1】:

这很尴尬...事实证明,性能相对较差是由于将我的测试代码作为简单 Web 应用程序的一部分运行(我知道,这在这个问题的上下文中没有意义) ,我使用lein ring server 运行它,我猜这与使用repl 运行它相同(我只是没有建立那个连接)。当我尝试使用lein uberjar 编译和打包,然后使用java -jar 执行该jar 时,它给了我与Java 应用程序相当的性能。

【讨论】:

  • 很高兴知道您找到了解决方法,我想我现在将删除我的“答案”。
  • 虽然看起来你也有一些有趣的发现@IvanKoblik :-) 我在 clojure 中的代码几乎慢了一倍,但这对我的情况来说是可以接受的,而且测试并不相等足以得出一个艰难的结论。我很高兴我没有找到破坏交易的方法,因为我喜欢到目前为止我用 Clojure 所做的一些事情。
最近更新 更多