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:
-
enkele
insertuitspraken , zoals in de vraag:INSERT INTO test (col1,col2,col3) VALUES (1,2,3) -
meerdere
insertuitspraken , zo geformatteerd:INSERT INTO test (col1,col2,col3) VALUES (1,2,3),(4,5,6),(7,8,9) -
load data infileverklaring , d.w.z. het laden van een eerder geschreven CSV-bestand inmysql: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 .