来自 RODBC 的 sqlQuery 上的 parlapply

Posted

技术标签:

【中文标题】来自 RODBC 的 sqlQuery 上的 parlapply【英文标题】:parlapply on sqlQuery from RODBC 【发布时间】:2014-07-02 22:05:56 【问题描述】:

R 版本:2.14.1 x64 在 Windows 7 上运行 连接到远程 Microsoft SQL Server 2012 上的数据库

我有一个无序的名字向量,比如:

names<-c(“A”, “B”, “A”, “C”,”C”)

每个在我的数据库中的表中都有一个 id。我需要将名称转换为其对应的 id。

我目前有以下代码来做。

###
names<-c(“A”, “B”, “A”, “C”,”C”)
dbConn<-odbcDriverConnect(connection=”connection string”) #successfully connects

nameToID<-function(name, dbConn)
                #dbConn : active db connection formed via odbcDriverConnect
                #name     : a char string

                sqlQuery(dbConn, paste(“select id from table where name=’”, name, “’”, sep=””))

sapply(names, nameToID, dbConn=dbConn)
###

除非有更好的方法来做到这一点,这可能涉及将表加载到 R 中,然后在那里解决问题(这是可能的),我理解为什么以下方法不起作用,但我似乎找不到解决方案。尝试通过包“parallel”使用并行化:

###
names<-c(“A”, “B”, “A”, “C”,”C”)
dbConn<-odbcDriverConnect(connection=”connection string”) #successfully connects

nameToID<-function(name, dbConn)
                #dbConn : active db connection formed via odbcDriverConnect
                #name     : a char string

                sqlQuery(dbConn, paste(“select id from table where name=’”, name, “’”, sep=””))


mc<-detectCores()
cl<-makeCluster(mc)
clusterExport(cl, c(“sqlQuery”, “dbConn”))
parSapply(cl, names, nameToID, dbConn=dbConn)    #incorrect passing of nameToID’s second argument
###

正如评论中所说,这不是将第二个参数分配给 nameToID 的正确方法。

我还尝试了以下方法:

parSapply(cl, names, function(x) nameToID(x, dbConn))

代替前面的 parSapply 调用,但这也不起作用,抛出错误说“第一个参数不是打开的 RODBC 连接”,可能是指 sqlQuery() 的第一个参数。 dbConn 仍然打开

以下代码确实适用于并行化。

###
names<-c(“A”, “B”, “A”, “C”,”C”)
dbConn<-odbcDriverConnect(connection=”connection string”) #successfully connects
nameToID<-function(name)
                #name     : a char string
                dbConn<-odbcDriverConnect(connection=”string”)
                result<-sqlQuery(dbConn, paste(“select id from table where name=’”, name, “’”, sep=””))
                odbcClose(dbConn)
                result


mc<-detectCores()
cl<-makeCluster(mc)
clusterExport(cl, c(“sqlQuery”, “odbcDriverConnect”, “odbcClose”, “dbConn”, “nameToID”))      #throwing everything in
parSapply(cl, names, nameToID)
###

但是连接的不断打开和关闭破坏了并行化的收益,看起来有点傻。

所以总体问题是如何将第二个参数(打开的数据库连接)传递给 parSapply 中的函数,其方式与常规应用中的方式大致相同?一般来说,如何将第二个、第三个、第 n 个参数传递给并行例程中的函数?

谢谢,如果您需要更多信息,请告诉我。

-DT

【问题讨论】:

【参考方案1】:

数据库连接对象不能作为函数参数导出或传递,因为它们包含套接字连接。如果您尝试,它将被序列化,发送到工作人员并反序列化,但由于套接字连接无效,因此无法正常工作。

解决方案是在调用 parSapply 之前在每个 worker 上创建数据库连接。我经常使用 clusterEvalQ 来做到这一点:

clusterEvalQ(cl, 
    library(RODBC)
    dbConn <- odbcDriverConnect(connection="connection string")
    NULL
)

现在worker函数可以写成:

nameToID <- function(name) 
    sqlQuery(dbConn, paste("select id from table where name='", name, "'", sep=""))

并调用:

parSapply(cl, names, nameToID)  

还要注意,由于 RODBC 已加载到每个工作程序上,因此您不必导出其中定义的函数,我认为这是一种很好的编程习惯。

【讨论】:

非常感谢史蒂夫,我感觉自己少了一步。使用 clusterEvalQ 在一个有点相关的主题中被提及,但我只是没有把它放在一起。这对我前进有很大帮助

以上是关于来自 RODBC 的 sqlQuery 上的 parlapply的主要内容,如果未能解决你的问题,请参考以下文章

RODBC-一个sqlQuery()调用中的多个表[重复]

如何让 sum 函数在 RODBC 中的 SQLquery 中工作

RODBC:为啥 sqlQuery() 中的空值和仅空格值的值为“NA”?

RODBC 在 sqlQuery() 的连接中使用 Data.Frame

RODBC 连接到 Mavericks 上的 SQL Server

RODBC sqlQuery() 在应该返回 varchar(MAX) 时返回 varchar(255)