【问题标题】:Insert file records into postgres db using clojure jdbc is taking long time compared to python psycopg2与 python psycopg2 相比,使用 clojure jdbc 将文件记录插入 postgres db 需要很长时间
【发布时间】:2016-07-03 16:58:09
【问题描述】:

我正在尝试将记录插入 postgres 数据库,它需要大约 3 个小时,而使用 python psycopg2 和 cursor.copy_from 方法需要 40 秒

我的代码出了什么问题,使用 clojure.java.jdbc/db-do-prepared 也需要大约 3 个小时。 请帮忙!

文件大小为 175M,有 409,854 条记录

(defn-
  str<->int [str]
  (let [n (read-string str)]
    (if (integer? n) n)))

(with-open [file (reader "/path/to/foo.txt")]
    (try
      (doseq [v (clojure-csv.core/parse-csv file)]

        (clojure.java.jdbc/insert! db  :records 
                      nil
                      [(v 0) (v 1) (v 2) (str<->int (v 3))]))
      (println "Records inserted successfully")
      (Exception e
        (println (.getNextException e) e))))

【问题讨论】:

    标签: java python postgresql jdbc clojure


    【解决方案1】:

    这可能是由于您的 Clojure 版本中没有使用批处理。您将触发提交的每一行一一插入。

    如果您想在 Clojure 中执行此操作,则需要将 CSV 文件中的 partition 行和 insert! 每个块作为一个批次提交。您需要使用接受多个col-val-vecs 的最后一个arity 版本。示例代码(未勾选,仅展示思路):

    (defn row->col-spec [row]
      [(v 0) (v 1) (v 2) (str<->int (v 3))])
    
    (with-open [csv-file (reader "/path/to/foo.txt")]
      (try
        (->> csv-file
             (clojure-csv.core/parse-csv)
             (map row->col-spec)
             (partition 50)
             (map (fn [batch] clojure.java.jdbc/insert! db :records ["col1" "col2" "col3" "col4"] batch))
             (dorun))
        (catch Exception e
          (println e))))
    

    如果您不必在 Clojure 中执行此操作,那么使用 psql's COPY 命令似乎是最简单和最快的选择:

    COPY records FROM '/path/to/foo.txt' WITH (FORMAT csv, DELIMITER ',',  NULL 'NULL');
    

    【讨论】:

    • 我使用的是 Clojure 版本 1.8.0,你能分享一个如何在 clojure 中完成的示例
    • 我在 Clojure 中添加了一个代码示例 - 测试它,因为我没有运行它。
    • 嗯,我使用了你建议的PSQL Copy命令,甚至不需要强制转换每个字段,这确实更容易更快。谢谢
    • 如果我想将复制命令作为 \copy 运行,考虑到在准备查询字符串时不能执行“\copy”,我将如何在 clojure 中执行此操作
    • @JobSam \copy 不是 SQL 命令,它是 psql "meta-command",不能通过 JDBC 使用。
    【解决方案2】:

    4 年后,决定回到这个问题并分享解决方案指南,我相信这将有助于某人入门。

    您可以查看 clojure.java.jdbc/insert-multi! 并进行适当编辑以适应数据库中的列类型

    (let [from "/path/to/foo.txt"
          to "/path/to/temp/foo.txt"]
      (with-open [reader (io/reader from)
                  writer (io/writer to)]
        (doall
          (->> (csv/read-csv reader)
               ;(drop 1)   ;if theres header
               (map #(list (nth % 0 nil) (nth % 2 nil)  (nth % 3 nil)))
               (csv/write-csv writer))))
      (let [fstream (slurp to)
            streamarray (map #(str/split % #",")
                             (str/split-lines fstream))]
        (clojure.java.jdbc/insert-multi! pg-db              ;connection or {:datasource hk-cp}
                                         :tbl_cdrs_da                 ;table name
                                         [:origin_node_type :origin_transaction_id :da_ua_id] ;colums
                                         streamarray)))               ;array
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      • 2021-07-24
      • 2016-08-13
      • 2017-12-05
      相关资源
      最近更新 更多