我想从数据库读取数百万行并写入文本文件。clojure.java.jdbc /查询大型结果集懒惰
这是我的问题的延续,现在database dump to text file with side effects
我的问题似乎是,记录不会发生,直到程序完成。另一个我没有处理的指标是,直到程序结束,文本文件才被写入。
根据IRC的提示,似乎我的问题可能与:result-set-fn
有关,并且在代码的clojure.java.jdbc/query
区域中默认为doall
。
我试图用for
函数替换它,但仍然发现内存消耗很高,因为它将整个结果集拉入内存。
我怎样才能有一个:result-set-fn
不拉像doall
像一切?如何在程序运行时逐渐写入日志文件,而不是在执行完成后转储所有内容?
(let [
db-spec local-postgres
sql "select * from public.f_5500_sf "
log-report-interval 1000
fetch-size 100
field-delim "\t"
row-delim "\n"
db-connection (doto (j/get-connection db-spec) (.setAutoCommit false))
statement (j/prepare-statement db-connection sql :fetch-size fetch-size)
joiner (fn [v] (str (join field-delim v) row-delim))
start (System/currentTimeMillis)
rate-calc (fn [r] (float (/ r (/ (- (System/currentTimeMillis) start) 100))))
row-count (atom 0)
result-set-fn (fn [rs] (lazy-seq rs))
lazy-results (rest (j/query db-connection [statement] :as-arrays? true :row-fn joiner :result-set-fn result-set-fn))
]; }}}
(.setAutoCommit db-connection false)
(info "Started dbdump session...")
(with-open [^java.io.Writer wrtr (io/writer "output.txt")]
(info "Running query...")
(doseq [row lazy-results]
(.write wrtr row)
))
(info (format "Completed write with %d rows" @row-count))
)
我已经添加的连接,进行的:结果类型只进,添加游标,使其成为:只读,并将获取大小设置为1000,然后设置为100.当我尝试获取更大的结果集时,我仍然用完了jvm堆大小。我已经更新了我的问题以包括新的代码...我在这方面有什么可以渴望的损失... – joefromct
@joefromct,尝试禁用autocommit - '(.setAutoCommit db-connection false) '。我将它添加到我的答案中的示例代码中。顺便说一下,部分难点在于'setFetchSize'仅仅是驱动程序的提示([根据API文档](http://docs.oracle.com/javase/1.5.0/docs/api/java/ sql/Statement.html#setFetchSize(int))),因此驱动程序之间的解释方式会有所不同。但是,PostgreSQL的[JDBC文档](http://jdbc.postgresql.org/documentation/head/query.html)表明它被支持,所以我认为我们只需要找到正确的咒语。 – jbm
为了澄清,'setFetchSize'是一个'prepare-statement'方法,它基于':fetch-size'参数在内部调用,而不是代码中需要的东西。 – jbm