我正试图将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
或我能想到的其他任何方法都没有太大帮助。:fetch-size
时,我的RAM不会爆炸(hocus pocus),因此传输很慢,DB连接的两个连接都在“ Activity ”和“事务中的空闲”状态之间切换。我从来没有等那么久才找到实际传输的任何数据!当我在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)))}))
我将不胜感激任何帮助或信息,我将不胜感激。
最佳答案
我认为这里的主要观察结果是,虽然您的查询是从一个数据库懒惰地流式传输结果,但是您的插入只是向另一个数据库的一个巨大写入。关于内存使用情况,如果最后要为单个写入操作收集所有这些结果(内存中),则我认为是否以延迟方式流式传输查询结果没有太大区别。
平衡内存使用量和吞吐量的一种方法是分批写入:
(db/with-db-transaction [tx {:datasource source-db}]
(db/query tx
[(db/prepare-statement (:connection tx)
answer-sql
{:result-type :forward-only
:concurrency :read-only
:fetch-size 2000})]
{:as-arrays? true
:result-set-fn (fn [result-set]
(let [keys (first result-set)
values (rest result-set)]
(doseq [batch (partition-all 2000 values)]
(db/insert-multi! {:datasource dct-db}
:dim_answers
keys
batch))))}))
不同之处在于,这是使用
partition-all
批量插入values
(与:fetch-size
大小相同,但我确定可以对其进行调整)。通过将JVM最大堆大小设置为-Xmx1g
之类,将这种方法的性能/内存使用与其他方法进行比较。我无法使用此堆大小来完成非批处理版本。我能够在大约1分钟内在笔记本电脑上的本地PostgreSQL数据库之间迁移600万个小块行,并使用java进行迁移。我也使用了HikariCP。
如果确实要分批插入,则如果适合您的用例,则可能需要考虑将所有插入物包装在单个事务中。为了简洁起见,我在此处省略了其他交易。
如果我不使用
:max-size
参数,内存会爆炸我在最新的clojure.java.jdbc中找不到对该选项的任何引用(除规范外),并且没有影响我的测试。我确实看到了
:max-rows
,但您当然不想要。我认为这是因为
:as-array
参数。我希望这对内存使用很有帮助。行向量应该比行映射更节省空间。