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
insert
uitspraken , zoals in de vraag:INSERT INTO test (col1,col2,col3) VALUES (1,2,3)
-
meerdere
insert
uitspraken , zo geformatteerd:INSERT INTO test (col1,col2,col3) VALUES (1,2,3),(4,5,6),(7,8,9)
-
load data infile
verklaring , 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 .