Улучшение производительности записи RODBC-Postgres - PullRequest
4 голосов
/ 19 апреля 2011

Я недавно начал использовать RODBC для подключения к PostgreSQL как Я не смог заставить RPostgreSQL скомпилировать и запустить в Windows x64 . Я обнаружил, что производительность чтения между двумя пакетами одинакова, но производительность записи - нет. Например, используя RODBC (где z - это кадр данных строки ~ 6.1M):

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()

Принимая во внимание, что для того же фрейма данных ~ 6.1M строки с использованием RPostgreSQL (под 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 примерно в 3 раза быстрее RODBC при написании таблиц. Это соотношение производительности остается более или менее постоянным независимо от количества строк в кадре данных (но количество столбцов оказывает гораздо меньшее влияние). Я заметил, что RPostgreSQL использует что-то вроде COPY <table> FROM STDIN, в то время как RODBC выдает кучу INSERT INTO <table> (columns...) VALUES (...) запросов. Я также заметил, что RODBC, кажется, выбирает int8 для целых чисел, тогда как RPostgreSQL выбирает int4 там, где это необходимо.

Мне нужно часто делать такого рода копии данных, поэтому я бы очень искренне был бы благодарен за любые советы по ускорению RODBC. Например, это просто присуще ODBC, или я не правильно его называю?

1 Ответ

1 голос
/ 22 апреля 2011

Кажется, что нет немедленного ответа на этот вопрос, поэтому я опубликую хитрый обходной путь на случай, если он кому-нибудь пригодится.

Sharpie верен - COPY FROM - самый быстрый способ получить данные в Postgres. Основываясь на его предположении, я взломал функцию, которая значительно повышает производительность по сравнению с RODBC::sqlSave(). Например, на запись кадра данных размером 1,1 миллиона строк (по 24 столбцам) потребовалось 960 секунд (прошло), используя sqlSave против 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)
...