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
insert
pernyataan , seperti pada pertanyaan:INSERT INTO test (col1,col2,col3) VALUES (1,2,3)
-
beberapa
insert
pernyataan , diformat seperti ini:INSERT INTO test (col1,col2,col3) VALUES (1,2,3),(4,5,6),(7,8,9)
-
load data infile
pernyataan , 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 .