sql >> Database >  >> RDS >> Mysql

Efficiënte manier om dataframe in te voegen van R naar SQL

TL;DR: LOAD DATA INFILE is één orde van grootte sneller dan meerdere INSERT statements, die zelf een orde van grootte sneller zijn dan enkele INSERT verklaringen.

Ik benchmark hieronder de drie belangrijkste strategieën om gegevens van R in Mysql te importeren:

  1. enkele insert uitspraken , zoals in de vraag:

    INSERT INTO test (col1,col2,col3) VALUES (1,2,3)

  2. meerdere insert uitspraken , zo geformatteerd:

    INSERT INTO test (col1,col2,col3) VALUES (1,2,3),(4,5,6),(7,8,9)

  3. load data infile verklaring , d.w.z. het laden van een eerder geschreven CSV-bestand in mysql :

    LOAD DATA INFILE 'the_dump.csv' INTO TABLE test

Ik gebruik RMySQL hier, maar elk ander mysql-stuurprogramma zou tot vergelijkbare resultaten moeten leiden. De SQL-tabel is gemaakt met:

CREATE TABLE `test` (
  `col1` double, `col2` double, `col3` double, `col4` double, `col5` double
) ENGINE=MyISAM;

De verbindings- en testgegevens zijn gemaakt in R met:

library(RMySQL)
con = dbConnect(MySQL(),
                user = 'the_user',
                password = 'the_password',
                host = '127.0.0.1',
                dbname='test')

n_rows = 1000000 # number of tuples
n_cols = 5 # number of fields
dump = matrix(runif(n_rows*n_cols), ncol=n_cols, nrow=n_rows)
colnames(dump) = paste0('col',1:n_cols)

Benchmarking enkele insert uitspraken:

before = Sys.time()
for (i in 1:nrow(dump)) {
  query = paste0('INSERT INTO test (',paste0(colnames(dump),collapse = ','),') VALUES (',paste0(dump[i,],collapse = ','),');')
  dbExecute(con, query)
}
time_naive = Sys.time() - before 

=> dit duurt ongeveer 4 minuten op mijn computer

Benchmarking van meerdere insert uitspraken:

before = Sys.time()
chunksize = 10000 # arbitrary chunk size
for (i in 1:ceiling(nrow(dump)/chunksize)) {
  query = paste0('INSERT INTO test (',paste0(colnames(dump),collapse = ','),') VALUES ')
  vals = NULL
  for (j in 1:chunksize) {
    k = (i-1)*chunksize+j
    if (k <= nrow(dump)) {
      vals[j] = paste0('(', paste0(dump[k,],collapse = ','), ')')
    }
  }
  query = paste0(query, paste0(vals,collapse=','))
  dbExecute(con, query)
}
time_chunked = Sys.time() - before 

=> dit duurt ongeveer 40 seconden op mijn computer

Benchmarking load data infile verklaring :

before = Sys.time()
write.table(dump, 'the_dump.csv',
          row.names = F, col.names=F, sep='\t')
query = "LOAD DATA INFILE 'the_dump.csv' INTO TABLE test"
dbSendStatement(con, query)
time_infile = Sys.time() - before 

=> dit duurt ongeveer 4 seconden op mijn computer

Het maken van uw SQL-query om veel invoegwaarden te verwerken, is de eenvoudigste manier om de prestaties te verbeteren. Overgaan naar LOAD DATA INFILE zal leiden tot een optimaal resultaat. Tips voor goede prestaties zijn te vinden in deze pagina met mysql-documentatie .




  1. Het uitvoeringsplan voor query's bekijken in Azure Data Studio (SQL Server)

  2. Hoe gebruik je scriptvariabelen in psql?

  3. Hoe kan ik verbinding maken met de Oracle Database 11g-server via ssh-tunnelketen (dubbele tunnel, server in bedrijfsnetwerk)?

  4. Hoe kom ik erachter of een upsert een update was met PostgreSQL 9.5+ UPSERT?