我想從數據庫讀取數百萬行並寫入文本文件。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