我正在尝试使用函数将数据库sql转储从select语句写入文本文件。返回的卷可能非常大,我有兴趣尽快做到这一点。
对于大的结果集,我还需要记录每个x-interval写入的总行数以及自上一个x-interval以来已写入的每秒行数。我有一个(地图)实际上在(打开)期间进行写操作,所以我相信记录行的副作用应该在那里发生。 (见代码中的评论)。
我的问题是:
固定宽度是否可以作为选项?我相信命名管道到批量加载器会更快。权衡将在磁盘I / O上代替下游解析的CPU利用率。但是,这可能需要对返回的结果集进行内省(使用.getMetaData?)
(ns metadata.db.table-dump
[:use
[clojure.pprint]
[metadata.db.connections]
[metadata.db.metadata]
[clojure.string :only (join)]
[taoensso.timbre :only (debug info warn error set-config!)]
]
[:require
[clojure.java.io :as io ]
[clojure.java.jdbc :as j ]
[clojure.java.jdbc.sql :as sql]
]
)
(set-config! [:appenders :spit :enabled?] true)
(set-config! [:shared-appender-config :spit-filename] "log.log")
(let [
field-delim "\t"
row-delim "\n"
report-seconds 10
sql "select * from comcast_lineup "
joiner (fn [v] (str (join field-delim v ) row-delim ) )
results (rest (j/query local-postgres [sql ] :as-arrays? true :row-fn joiner ))
]
(with-open [wrtr (io/writer "test.txt")]
(doall
(map #(.write wrtr %)
; Somehow in here i want to log with (info ) rows written so
; far, and "rows per second" every 10 seconds.
results ))
) (info "Completed write") )
答案 0 :(得分:1)
您可以从Idiomatic clojure for progress reporting?
的答案中获得一些用处具体到你的情况
1)您可以将一个索引添加到地图中作为匿名函数的第二个参数,然后在您映射的函数中查看索引以查看您正在编写的行。可以用来更新原子。
user> (def stats (atom {}))
#'user/stats
user> (let [start-time (. (java.util.Date.) getTime)]
(dorun (map (fn [line index]
(println line) ; write to log file here
(reset! stats [{:lines index
:start start-time
:end (. (java.util.Date.) getTime)}]))
["line1" "line2" "line3"]
(rest (range)))))
line1
line2
line3
nil
user> @stats
[{:lines 3, :start 1383183600216, :end 1383183600217}]
user>
然后可以每隔几秒打印/记录stats
的内容以更新UI
3)您肯定希望使用dorun
而不是doall
,因为您怀疑这将在足够大的数据集上耗尽内存。 dorun
会在编写结果时删除结果,因此如果您想等待足够长的时间,可以在无限大的数据上运行它。
答案 1 :(得分:1)
情侣一般提示:
setFetchSize
以避免在进入Clojure之前将整个结果集加载到RAM中。请参阅What does Statement.setFetchSize(nSize) method really do in SQL Server JDBC driver? doall
确实会迫使整个事情进入RAM;尝试doseq
而不是atom
来保留随时写入的行数;你可以用它来写行 - 远等等。草图:
(let [ .. your stuff ..
start (System/currentTimeMillis)
row-count (atom 0)]
(with-open [^java.io.Writer wrtr (io/writer "test.txt")]
(doseq [row results]
(.write wrtr row)
(swap! row-count inc)
(when (zero? (mod @row-count 10000))
(println (format "written %d rows" @row-count))
(println (format "rows/s %.2f" (rate-calc-here)))))))