通过 R 将数据上传到 PostgresSQL 12 的最快方法

Dyl*_*ell 4 postgresql odbc r google-cloud-sql

我使用以下代码连接到 PostgreSQL 12 数据库:

con <- DBI::dbConnect(odbc::odbc(), driver, server, database, uid, pwd, port)
Run Code Online (Sandbox Code Playgroud)

这将我连接到 Google Cloud SQL 上的 PostgreSQL 12 数据库。然后使用以下代码上传数据:

DBI::dbCreateTable(con, tablename, df)
DBI::dbAppendTable(con, tablename, df)
Run Code Online (Sandbox Code Playgroud)

其中df是我在 R 中创建的数据框。该数据框由约 550,000 条记录组成,总计 713 MB 数据。

通过上述方法上传时,以每秒40次写入操作的速度,大约需要9个小时。有没有更快的方法将此数据上传到我的 PostgreSQL 数据库(最好通过 R)?

r2e*_*ans 9

我一直发现批量复制是最好的,在 R 外部。插入可以明显更快,并且您的开销是(1)写入文件,以及(2)更短的运行时间。

本次测试的设置:

  • 赢10 (2004)
  • 泊坞窗
  • postgres:11 容器,在本地主机上使用端口 35432,简单身份验证
  • 主机操作系统中的二进制文件psql(R 正在运行);对于linux来说应该很容易,对于windows我从https://www.postgresql.org/download/windows/获取了“zip”(不是安装程序)文件获取了“zip”(不是安装程序)文件并提取了我需要的内容
  • 我用来data.table::fwrite保存文件是因为它速度很快;在这种情况下write.tablewrite.csv仍然比使用快得多DBI::dbWriteTable,但是根据您的数据大小,您可能更喜欢快速的东西
DBI::dbCreateTable(con2, "mt", mtcars)
DBI::dbGetQuery(con2, "select count(*) as n from mt")
#   n
# 1 0

z1000 <- data.table::rbindlist(replicate(1000, mtcars, simplify=F))
nrow(z1000)
# [1] 32000
system.time({
  DBI::dbWriteTable(con2, "mt", z1000, create = FALSE, append = TRUE)
})
#    user  system elapsed 
#    1.56    1.09   30.90 

system.time({
  data.table::fwrite(z1000, "mt.csv")
  URI <- sprintf("postgresql://%s:%s@%s:%s", "postgres", "mysecretpassword", "127.0.0.1", "35432")
  system(
    sprintf("psql.exe -U postgres -c \"\\copy %s (%s) from %s (FORMAT CSV, HEADER)\" %s",
            "mt", paste(colnames(z1000), collapse = ","),
            sQuote("mt.csv"), URI)
  )
})    
# COPY 32000
#    user  system elapsed 
#    0.05    0.00    0.19 
DBI::dbGetQuery(con2, "select count(*) as n from mt")
#       n
# 1 64000
Run Code Online (Sandbox Code Playgroud)

虽然这比您的数据(32K 行、11 列、1.3MB 数据)小很多,但从 30 秒到不到 1 秒的加速是不容忽视的。


旁注:(dbAppendTable慢) 和dbWriteTable. 比较psql这两个函数:

z100 <- rbindlist(replicate(100, mtcars, simplify=F))

system.time({
  data.table::fwrite(z100, "mt.csv")
  URI <- sprintf("postgresql://%s:%s@%s:%s", "postgres", "mysecretpassword", "127.0.0.1", "35432")
  system(
    sprintf("/Users/r2/bin/psql -U postgres -c \"\\copy %s (%s) from %s (FORMAT CSV, HEADER)\" %s",
            "mt", paste(colnames(z100), collapse = ","),
            sQuote("mt.csv"), URI)
  )
})
# COPY 3200
#    user  system elapsed 
#     0.0     0.0     0.1 

system.time({
  DBI::dbWriteTable(con2, "mt", z100, create = FALSE, append = TRUE)
})
#    user  system elapsed 
#    0.17    0.04    2.95 

system.time({
  DBI::dbAppendTable(con2, "mt", z100, create = FALSE, append = TRUE)
})
#    user  system elapsed 
#    0.74    0.33   23.59 
Run Code Online (Sandbox Code Playgroud)

(我不想和上面的时间dbAppendTable在一起z1000......)

(为了好玩,我再次运行了和replicate(10000, ...)测试,它们分别花了 2 秒和 372 秒。你的选择:-) ... 现在我有超过 650,000 行... hrmph ... .. 。psqldbWriteTablemtcarsdrop table mt