2012-03-29 5 views
14

Ich habe sechs SQL-Abfragen, die ich Skript R, die jeweils sehr lange dauern (~ 30 Minuten). Sobald jede Abfrage zurückgegeben wird, manipuliere ich die Daten für einige Standardberichte.Parallelisierung von SQL-Abfragen in R

Was Ich mag würde zu tun ist, verwenden, um meine Multi-Core-Maschine, diese SQL-Anfragen parallel von R.

Ich bin auf einem Windows-Rechner mit einer Oracle-DB zu laufen. Ich folgte einem blog post, um doSNOW und foreach zu verwenden, um diese Anforderungen zu versuchen und zu teilen, und das ist das beste Ding, das ich auf stackoverflow finden kann.

Ich konnte den Prozess für die nicht-parallele% do% Version von foreach, aber nicht die% Dopar% arbeiten. Mit% dopar% gibt es nur eine leere Menge zurück. Im Folgenden finden Sie einen Code, der Tabellen erstellt und die Abfragen ausführt, damit Sie sehen können, was passiert. Entschuldigung im Voraus, wenn es zu viel Basiscode gibt.

Ich habe mir einige der anderen R-Pakete angesehen, aber keine offensichtliche Lösung gefunden. Auch wenn Sie einen besseren Weg haben, um diese Art von Prozess zu verwalten, wäre ich daran interessiert, es zu hören - denken Sie daran, ich bin ein Analyst und kein Informatiker. Vielen Dank!

#Creating a cluster 
library(doSNOW) 
cl <- makeCluster(c("localhost","localhost"), type = "SOCK") 
registerDoSNOW(cl) 

#Connecting to database through RODBC 
ch=odbcConnect("",pwd = "xxxxx", believeNRows=FALSE) 
#Test connection 
odbcGetInfo(ch) 

#Creating database tables for example purposes 
qryA1 <- "create table temptable(test int)" 
qryA2 <- "insert into temptable(test) values((1))" 
qryA3 <- "select * from temptable" 
qryA4 <- "drop table temptable" 
qryB1 <- "create table temptable2(test int)" 
qryB2 <- "insert into temptable2(test) values((2))" 
qryB3 <- "select * from temptable2" 
qryB4 <- "drop table temptable2" 

sqlQuery(ch, qryA1) 
sqlQuery(ch, qryA2) 
doesItWork <- sqlQuery(ch, qryA3) 
doesItWork 
sqlQuery(ch, qryB1) 
sqlQuery(ch, qryB2) 
doesItWork <- sqlQuery(ch, qryB3) 
doesItWork 

result = c() 
output = c() 
databases <- list('temptable','temptable2') 


#Non-parallel version of foreach 
system.time(
foreach(i = 1:2)%do%{ 
result<-sqlQuery(ch,paste('SELECT * FROM ',databases[i])) 
output[i] = result 
} 
) 

output 

#Parallel version of foreach 

outputPar = c() 

system.time(
foreach(i = 1:2)%dopar%{ 
#Connecting to database through RODBC 
ch=odbcConnect(dsn ,pwd = "xxxxxx", believeNRows=FALSE) 
#Test connection 
odbcGetInfo(ch) 
result<-sqlQuery(ch,paste('SELECT * FROM ',databases[i])) 
outputPar[i] = result 
} 
) 

outputPar 

sqlQuery(ch, qryA4) 
sqlQuery(ch, qryB4) 
+2

Abfrage der Datenbank parallel nur der Prozess langsamer machen kann, je nachdem, was den Engpass verursacht. Sind Sie sicher, dass der Engpass die R-Instanz ist, die auf Ihrem Computer ausgeführt wird (nicht die Datenbank, die Netzwerkverbindung, der Computer, auf dem die Datenbank ausgeführt wird usw.)? –

+0

Wird das 'RODBC'-Paket auf den Clusterknoten geladen? Wenn nicht, füge '.packages =" RODBC "' zu deinem 'foreach()' Aufruf hinzu. – BenBarnes

+0

@Joshua Ulrich - Die Datenbank ist ziemlich robust, da es sich um eine kommerzielle Oracle-Installation handelt. Die Abfragen verbinden sich nur über mehrere Tabellen hinweg, die viel Verarbeitung in der Datenbank erfordern. Der manuelle Weg, den ich beschleunigen würde, besteht darin, mehrere Instanzen von SQL Developer zu initiieren, aber ein R-Skript macht viel von der Postabfrageverarbeitung für mich, daher würde ich lieber mehrere Abfragen gleichzeitig initiieren, so dass die längste Zeit, die ich habe warten müssen ist die lange Abfragezeit anstatt alle Abfragezeiten zusammen zu addieren. –

Antwort

9

Wenn Sie die Zuordnung outputPar[i] = result innerhalb der seriellen foreach-Schleife machen, dies in Ordnung ist (aber nicht wirklich die beabsichtigte Verwendung von foreach). Wenn Sie diese Zuweisung in der parallelen Schleife vornehmen, ist dies nicht OK. Eine ähnliche Frage, die David Smith bei Revolution beantwortete, findet sich unter http://tolstoy.newcastle.edu.au/R/e10/help/10/04/3237.html.

Als Lösung

system.time(
    outputPar <- foreach(i = 1:2, .packages="RODBC")%dopar%{ 
#Connecting to database through RODBC 
    ch=odbcConnect(dsn ,pwd = "xxxxxx", believeNRows=FALSE) 
#Test connection 
    odbcGetInfo(ch) 
    result<-sqlQuery(ch,paste('SELECT * FROM ',databases[i])) 
    result 
} 
) 
+1

Sehr schön - Ich habe den% dopar% Code wie folgt geändert und es hat funktioniert. Danke für die Hilfe Jungs. 'system.time ( test <- foreach (i = 1: 2, .packages =" RODBC ")% dopar% { # Verbindung zur Datenbank über RODBC ch = odbcConnect (dsn, pwd =" xxxxxxx ", believeNRows = FALSE) #Test Verbindung odbcGetInfo (ch) sqlquery (ch, paste ('SELECT * FROM', Datenbanken [i])) } ) test' –

Verwandte Themen