【发布时间】:2018-02-06 22:08:36
【问题描述】:
我正在尝试将 5,000,000 行从一个 Postgre DB 移动到另一个。两个连接都在 Hikari CP 连接池中。
我浏览了很多文档和帖子。它给我留下了下面的代码。但它并不是真的有用:
(jdbc/with-db-connection [tx {:datasource source-db}]
(jdbc/query tx
[(jdbc/prepare-statement (jdbc/get-connection tx)
answer-sql
{:fetch-size 100000})]
{:result-set-fn (fn [result-set]
(jdbc/insert-multi!
{:datasource target-db}
:migrated_answers
result-set))}))
我已经尝试了很多不同的形式。 jdbc/with-db-transaction 或任何其他我能想到的都没有多大帮助。
很多教程和帖子只提到如何将结果作为一个整体进行处理。进入 RAM 的小桌子绝对没问题,但看起来很快。但事实并非如此。
-
因此,当我正确使用
:fetch-size并且我的 RAM 不会爆炸(诡计)时,传输速度非常慢,因为两个连接在 DB 端的“活动”和“事务空闲”状态之间切换。我从来没有等过这么久才能找到实际传输的任何数据!当我在 Talend Open Studio(生成 Java 代码的 ETL 工具)中创建这个简单的批处理时,它会在 5 分钟内传输所有数据。并且光标大小“也”设置为 100000 那里。我认为 Clojure 的干净代码应该更快。
-
我得到的最快结果是使用下面的代码。我认为这是因为
:as-array参数。如果我不使用:max-rows参数内存会爆炸,因为它没有被延迟处理,所以我不能将它用于整个transfet。为什么?我不明白这里的规则。(jdbc/with-db-transaction [tx {:datasource source-db}] (jdbc/query tx [(jdbc/prepare-statement (:connection tx) answer-sql {:result-type :forward-only :concurrency :read-only :fetch-size 2000 :max-size 250000})] {:as-arrays? true :result-set-fn (fn [result-set] (let [keys (first result-set) values (rest result-set)] (jdbc/insert-multi! {:datasource dct-db} :dim_answers keys values)))}))
如果我明显缺少任何帮助或信息,我将不胜感激。
【问题讨论】:
-
这个问题可能会有所帮助:stackoverflow.com/questions/39765943/…
-
理论上,我认为最佳方法是通过管道input 和output 流连接一对
pgjdbcCopyManagers,每个流在自己的线程中运行。不过,不知道这在 Clojure 中是什么样子的...... -
你看过这个操作生成的 Talend 的代码吗?它对我来说似乎不是很优化。但我愿意接受任何澄清这一声明的建议:)
-
代码的主观简洁性通常与其性能无关(反之亦然!)。
标签: java postgresql jdbc clojure lazy-evaluation