提高 RODBC-Postgres 写入性能

Posted

技术标签:

【中文标题】提高 RODBC-Postgres 写入性能【英文标题】:Improving RODBC-Postgres Write Performance 【发布时间】:2011-04-18 20:47:57 【问题描述】:

我最近开始使用 RODBC 作为I couldn't get RPostgreSQL to compile and run in Windows x64 连接到 PostgreSQL。我发现两个包之间的读取性能相似,但写入性能则不然。例如,使用 RODBC(其中 z 是 ~610 万行数据帧):

library(RODBC)
con <- odbcConnect("PostgreSQL84")

#autoCommit=FALSE seems to speed things up
odbcSetAutoCommit(con, autoCommit = FALSE)
system.time(sqlSave(con, z, "ERASE111", fast = TRUE))

user  system elapsed
275.34  369.86 1979.59 

odbcEndTran(con, commit = TRUE)
odbcCloseAll()

而对于使用 RPostgreSQL(32 位以下)的相同 ~610 万行数据帧:

library(RPostgreSQL)
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, dbname="gisdb", user="postgres", password="...")
system.time(dbWriteTable(con, "ERASE222", z))

user  system elapsed 
467.57   56.62  668.29 

dbDisconnect(con)

因此,在这个测试中,RPostgreSQL 在写表方面的速度大约是 RODBC 的 3 倍。无论数据框中的行数如何,这个性能比似乎都保持不变(但列数的影响要小得多)。我确实注意到 RPostgreSQL 使用类似 COPY &lt;table&gt; FROM STDIN 的东西,而 RODBC 发出一堆 INSERT INTO &lt;table&gt; (columns...) VALUES (...) 查询。我还注意到 RODBC 似乎为整数选择了 int8,而 RPostgreSQL 在适当的地方选择了 int4。

我需要经常做这种数据帧复制,所以我会非常真诚地感谢任何关于加速 RODBC 的建议。例如,这只是 ODBC 固有的,还是我没有正确调用它?

【问题讨论】:

根据我将大量数据填充到 Postgres 的有限经验,从 INSERT INTO 切换到 COPY 是获得可接受性能的必要条件。 【参考方案1】:

似乎没有直接的答案,所以我会发布一个笨拙的解决方法,以防它对任何人都有帮助。

Sharpie 是正确的——COPY FROM 是迄今为止将数据导入 Postgres 的最快方式。根据他的建议,我组合了一个函数,该函数比RODBC::sqlSave() 显着提高了性能。例如,通过sqlSave 写入 110 万行(24 列)数据帧需要 960 秒(经过),而使用下面的函数需要 69 秒。我没想到会这样,因为数据会先写入磁盘,然后再写入数据库。

library(RODBC)
con <- odbcConnect("PostgreSQL90")

#create the table
createTab <- function(dat, datname) 

  #make an empty table, saving the trouble of making it by hand
  res <- sqlSave(con, dat[1, ], datname)
  res <- sqlQuery(con, paste("TRUNCATE TABLE",datname))

  #write the dataframe
  outfile = paste(datname, ".csv", sep = "")
  write.csv(dat, outfile)
  gc()   # don't know why, but memory is 
         # not released after writing large csv?

  # now copy the data into the table.  If this doesn't work,
  # be sure that postgres has read permissions for the path
  sqlQuery(con,  
  paste("COPY ", datname, " FROM '", 
    getwd(), "/", datname, 
    ".csv' WITH NULL AS 'NA' DELIMITER ',' CSV HEADER;", 
    sep=""))

  unlink(outfile)


odbcClose(con)

【讨论】:

不确定是否可以打开连接,然后将csv文件写入其中,以避免额外的写入...

以上是关于提高 RODBC-Postgres 写入性能的主要内容,如果未能解决你的问题,请参考以下文章

es 大批量写入提高性能的策略

在进行大量写入时提高 neo4j 性能

数据库调优过程:提高数据库写入性能方案调查

使用经 EMRFS S3 优化的提交器提高 Apache Spark 写入 Apache Parquet 格式文件的性能

如何提高MFC fprint的写作性能?

提高MySQL的IO性能需要知道的一些事情