2011-04-18 72 views
4

我最近开始使用RODBC连接到PostgreSQL作为I couldn't get RPostgreSQL to compile and run in Windows x64。我发现这两个软件包的读取性能是相似的,但写入性能不是。例如,使用RODBC(其中z是一〜6.1M行数据帧):改进RODBC-Postgres的写入性能

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同一〜6.1M行数据帧(在32位):

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 <table> FROM STDIN的东西,而RODBC发出一堆INSERT INTO <table> (columns...) VALUES (...)查询。我还注意到RODBC似乎选择int8作为整数,而RPostgreSQL在适当的情况下选择int4。

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

+0

在我有限的经验中,将大量数据填充到Postgres中,从'INSERT INTO'切换到'COPY'是可接受性能的必要条件。 – Sharpie 2011-04-19 03:53:32

回答

1

看起来没有即时的答案,所以我会发布一个kludgy解决方法,以防万一它对任何人都有帮助。

夏普是正确的 - 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) 
+0

不知道您是否可以打开连接,然后将csv文件写入它,以避免额外写入... – 2014-04-02 23:45:20