每次在 MySQL DB 中加载 R 输出
Posted
技术标签:
【中文标题】每次在 MySQL DB 中加载 R 输出【英文标题】:Load the R output eachtime in MySQL DB 【发布时间】:2014-03-21 02:17:36 【问题描述】:我有一个循环,它对数据框中的每一行进行迭代并生成 5 个输出文件 并继续为所有记录附加到同一个文件 - 代码工作正常。
for (n in 1:nrow(Data))
#Initialize the required variables
(some function ---)
#Write the file into the output file
df1= data.frame (key,value)
df2= data.frame (key,value)
df3= data.frame (key,value)
df4= data.frame (key,value)
df5= data.frame (key,value)
write.table(df1, file = paste(pradd,"table1.tsv",sep="/"), append = TRUE, quote = FALSE, sep = "\t")
write.table(df2, file = paste(pradd,"table2.tsv",sep="/"), append = TRUE, quote = FALSE, sep = "\t")
write.table(df3, file = paste(pradd,"table3.tsv",sep="/"), append = TRUE, quote = FALSE, sep = "\t")
write.table(df4, file = paste(pradd,"table4.tsv",sep="/"), append = TRUE, quote = FALSE, sep = "\t")
write.table(df5, file = paste(pradd,"table5.tsv",sep="/"), append = TRUE, quote = FALSE, sep = "\t")
但是我想加载输出 - 直接从 R 到 mysql DB 作为五个表。 这 5 个文件很大,我必须使用库来更快地加载到 db 表中。
我正在使用RODBC
连接到 MySQL。通过建立连接,我可以将 MySQL 表读入 R。不知道如何每次加载 5 个表 - 我的 for 循环运行。
更新:
我试过下面的代码——它正在加载——但是sqlQuery
很慢。我的for循环处理很快,但是当我尝试加载到数据库时它很慢。
for (i in 1: nrow(Data))
(--Some function to create dataset 1 to dataset 4 --- )
# collect the result in dataset1 and put them in a .txt file and use the .txt file to load into db
write.table(dataset1 , file1.txt, append=False, sep = "\t")
sqlQuery(channel," LOAD DATA LOCAL INFILE 'file1.txt' INTO TABLE lta_r_db.file1 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\\n';")
# collect the result in dataset2 and put them in a .txt file and use the .txt file to load into db
write.table(dataset2 , file2.txt, append=False, sep = "\t")
sqlQuery(channel," LOAD DATA LOCAL INFILE 'file2.txt' INTO TABLE lta_r_db.file2 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\\n';")
write.table(dataset3 , file3.txt, append=False, sep = "\t")
sqlQuery(channel," LOAD DATA LOCAL INFILE 'file3.txt' INTO TABLE lta_r_db.file3 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\\n';")
write.table(dataset4 , file4.txt, append=False, sep = "\t")
sqlQuery(channel," LOAD DATA LOCAL INFILE 'file4.txt' INTO TABLE lta_r_db.file4 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\\n';")
write.table(dataset5 , file5.txt, append=False, sep = "\t")
sqlQuery(channel," LOAD DATA LOCAL INFILE 'file5.txt' INTO TABLE lta_r_db.file5 FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\\n';")
我怎样才能在处理能力得到很大改善的情况下运行上述内容。
【问题讨论】:
【参考方案1】:在这里,您可以找到另一种使用虚构数据的方法 ..
以下代码测试使用base::mapply
和parallel::mcmapply
在带有RMySQL::dbWriteTable
的mysql 数据库中重复插入data.frame 列表
还要考虑到,一般来说,对数据库的少数访问(以及每次访问的更多数据)越好。作为替代方案,您可以尝试在 R 中将数据打包到较大的表中,然后将它们导出到 mysql。
不过mysql这边..
## mysql> show tables;
## +----------------+
## | Tables_in_test |
## +----------------+
## | table1 |
## | table2 |
## | table3 |
## | table4 |
## | table5 |
## +----------------+
## 5 rows in set (0.00 sec)
## mysql> describe table1;
## +-------+---------+------+-----+---------+-------+
## | Field | Type | Null | Key | Default | Extra |
## +-------+---------+------+-----+---------+-------+
## | id | int(11) | YES | | NULL | |
## | value | float | YES | | NULL | |
## +-------+---------+------+-----+---------+-------+
## 2 rows in set (0.00 sec)
然后
## ## ----------------------------------------------------------
## ## A few benchmark
## ## ----------------------------------------------------------
## Create some data
id <- 1:5
val <- rnorm(5)
## you need to have a list of data.frame, eg
my.df <- data.frame("id"= 1:5,
"value"=rnorm(5))
df.list <- split(my.df, my.df$id)
## otherwise
## df.list <- list(df1,df2,df3,df4,df5)
tab.names <- paste("table", 1:5, sep="")
## number of repetitions
reps <- 100
clean <- function()
dbSendQuery(my.con, "delete from table1")
dbSendQuery(my.con, "delete from table2")
dbSendQuery(my.con, "delete from table3")
dbSendQuery(my.con, "delete from table4")
dbSendQuery(my.con, "delete from table5")
## ## -------------------------------------------------------
library(RMySQL)
library(parallel)
my.con <- dbConnect(MySQL(),
host = "localhost",
dbname = "test",
user = "your.username",
password = "your.password")
clean()
system.time(
for (i in 1:reps)
mapply(dbWriteTable,
name=tab.names ,
value = df.list,
MoreArgs=list(conn = my.con, append = T,
row.names = FALSE))
)
clean()
system.time(
for (i in 1:reps)
mcmapply(dbWriteTable,
name=tab.names ,
value = df.list,
MoreArgs=list(conn = my.con, append = T,
row.names = FALSE),
mc.cores = 8,
mc.preschedule = FALSE
)
)
clean()
dbDisconnect(my.con)
rm(my.con)
我没有发现使用并行化可以提高速度。 最后,至少在我的设置中,你可以使用一个简单的
mapply(dbWriteTable,
name=paste("table", 1:5, sep="") ,
value = df.list,
MoreArgs=list(conn = my.con, append = T, row.names = FALSE))
我在 unix 中不经常使用 ODBC,所以我无法针对 RODBC 进行测试,但是 HTH。
干杯
【讨论】:
【参考方案2】:确保您的 data.frame 与数据库中的表具有相同数量的变量和相同的变量名称。
#your connection to the MySQL database
library(RODBC)
channel <- odbcConnect()
for (n in 1:nrow(Data))
#Initialize the required variables
(some function ---)
#Write the file into the output file
df1= data.frame (key,value)
sqlSave(channel = channel, dat = df1, tablename = "table1", append = TRUE)
odbcClose(channel)
【讨论】:
它可以工作,但是 sqlSave 很慢,如何在向其中插入更多记录时运行得更快 df1 有多少行?只有一个? sqlSave() 可以同时保存多条记录。但这可能需要您重写一些代码。看一下 ?sqlQuery() ,它允许在数据库上应用任何 SQL 命令。 我已根据建议更新了问题。我试过sqlQuery(channel,"BULK INSERT dbname.tablename FROM 'C:/Users/xx/Desktop/xx/Temp/xx/Fc/df1.txt' WITH ( FIELDTERMINATOR = ',',ROWTERMINATOR = '\\n' )")
但是我得到了 Errro:Couldnot SQL:ExecDirect
我根据您的建议更新了问题。但是处理比sqlSave
好10倍,但仍然运行更长时间
我已经更正了我的代码。您不需要在 sqlSave 中引用 df1。以上是关于每次在 MySQL DB 中加载 R 输出的主要内容,如果未能解决你的问题,请参考以下文章