TL;DR: LOAD DATA INFILE adalah satu urutan besarnya lebih cepat daripada beberapa INSERT pernyataan, yang sendiri satu urutan besarnya lebih cepat dari INSERT tunggal pernyataan.
Saya membandingkan di bawah tiga strategi utama untuk mengimpor data dari R ke Mysql:
-
satu
insertpernyataan , seperti pada pertanyaan:INSERT INTO test (col1,col2,col3) VALUES (1,2,3) -
beberapa
insertpernyataan , diformat seperti ini:INSERT INTO test (col1,col2,col3) VALUES (1,2,3),(4,5,6),(7,8,9) -
load data infilepernyataan , yaitu memuat file CSV yang ditulis sebelumnya dimysql:LOAD DATA INFILE 'the_dump.csv' INTO TABLE test
Saya menggunakan RMySQL di sini, tetapi driver mysql lainnya harus mengarah ke hasil yang serupa. Tabel SQL dibuat dengan:
CREATE TABLE `test` (
`col1` double, `col2` double, `col3` double, `col4` double, `col5` double
) ENGINE=MyISAM;
Koneksi dan data uji dibuat di R dengan:
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)
Pembandingan tunggal insert pernyataan:
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
=> ini membutuhkan waktu sekitar 4 menit di komputer saya
Pembandingan beberapa insert pernyataan:
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
=> ini membutuhkan waktu sekitar 40 detik di komputer saya
Pembandingan load data infile pernyataan :
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
=> ini membutuhkan waktu sekitar 4 detik di komputer saya
Membuat kueri SQL Anda untuk menangani banyak nilai sisipan adalah cara paling sederhana untuk meningkatkan kinerja. Transisi ke LOAD DATA INFILE akan memberikan hasil yang optimal. Kiat kinerja yang baik dapat ditemukan di halaman dokumentasi mysql ini .