web-dev-qa-db-fra.com

Comment exporter rapidement des données de R vers SQL Server

La fonction sqlSave du package RODBC standard, même sous la forme d'une seule instruction INSERT (paramètre fast = TRUE), est extrêmement lente pour les grandes quantités de données en raison d'un chargement non minimal. Comment pourrais-je écrire des données sur mon serveur SQL avec une journalisation minimale pour qu'il écrive beaucoup plus rapidement?

J'essaie actuellement:

toSQL = data.frame(...);
sqlSave(channel,toSQL,tablename="Table1",rownames=FALSE,colnames=FALSE,safer=FALSE,fast=TRUE);
16
jpd527

En écrivant les données sur un fichier CSV localement, puis en utilisant un BULK INSERT (non disponible comme fonction prédéfinie semblable à sqlSave), les données peuvent être écrites très rapidement sur le serveur MS SQL.

toSQL = data.frame(...);
write.table(toSQL,"C:\\export\\filename.txt",quote=FALSE,sep=",",row.names=FALSE,col.names=FALSE,append=FALSE);
    sqlQuery(channel,"BULK
                INSERT Yada.dbo.yada
                FROM '\\\\<server-that-SQL-server-can-see>\\export\\filename.txt'
                WITH
                (
                FIELDTERMINATOR = ',',
                ROWTERMINATOR = '\\n'
                )");

SQL Server doit avoir la permission d'accéder au dossier réseau contenant le fichier CSV, sinon ce processus ne fonctionnera pas. Bien que cela nécessite certaines configurations avec diverses autorisations (le dossier réseau et les privilèges BULK ADMIN, la récompense en vitesse est infiniment plus précieuse).

29
jpd527

Je suis tout à fait d’accord que BULK INSERT est la bonne option pour toutes les données qui sont non minuscules . Toutefois, dans le cas où vous auriez besoin d’ajouter 2 ou 3 lignes, par exemple. message de débogage BULK INSERT semble être une overkill.

La réponse à votre question serait une fonction DBI::dbWriteTable(). Exemple ci-dessous (je connecte mon code R à l'instance AWS RDS de MS SQL Express):

library(DBI)
library(RJDBC)
library(tidyverse)

# Specify where you driver lives
drv <- JDBC(
  "com.Microsoft.sqlserver.jdbc.SQLServerDriver",
  "c:/R/SQL/sqljdbc42.jar") 

# Connect to AWS RDS instance
conn <- drv %>%
  dbConnect(
    Host = "jdbc:sqlserver://xxx.ccgqenhjdi18.ap-southeast-2.rds.amazonaws.com",
    user = "xxx",
    password = "********",
    port = 1433,
    dbname= "qlik")

if(0) { # check what the conn object has access to
  queryResults <- conn %>%
    dbGetQuery("select * from information_schema.tables")
}

# Create test data
example_data <- data.frame(animal=c("dog", "cat", "sea cucumber", "sea Urchin"),
                           feel=c("furry", "furry", "squishy", "spiny"),
                           weight=c(45, 8, 1.1, 0.8))
# Works in 20ms in my case
system.time(
  conn %>% dbWriteTable(
    "qlik.export.test",
    example_data
  )
)

# Let us see if we see the exported results
conn %>% dbGetQuery("select * FROM qlik.export.test")

# Let's clean the mess and force-close connection at the end of the process
conn %>% dbDisconnect()

Cela fonctionne assez rapidement pour de petites quantités de données transférées et semble assez élégant si vous voulez une solution data.frame -> SQL table.

Prendre plaisir!

0
Alex Skorokhod