Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wydajny sposób wstawiania ramki danych z R do SQL

TL;DR: LOAD DATA INFILE jest o jeden rząd wielkości szybszy niż wiele INSERT instrukcje, które same są o jeden rząd wielkości szybsze niż pojedyncze INSERT oświadczenia.

Poniżej porównam trzy główne strategie importowania danych z R do Mysql:

  1. pojedynczy insert oświadczenia , jak w pytaniu:

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

  2. wiele insert oświadczenia , sformatowany tak:

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

  3. load data infile oświadczenie , czyli ładowanie wcześniej napisanego pliku CSV w mysql :

    LOAD DATA INFILE 'the_dump.csv' INTO TABLE test

Używam RMySQL tutaj, ale każdy inny sterownik mysql powinien prowadzić do podobnych wyników. Utworzono instancję tabeli SQL za pomocą:

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

Połączenie i dane testowe zostały utworzone w R z:

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)

Porównanie pojedynczego insert oświadczenia:

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 

=> zajmuje to około 4 minuty na moim komputerze

Porównanie wielu insert oświadczenia:

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 

=> zajmuje to około 40 sekund na moim komputerze

Benchmarking load data infile oświadczenie :

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 

=> zajmuje to około 4 sekundy na moim komputerze

Stworzenie zapytania SQL do obsługi wielu wartości wstawiania to najprostszy sposób na poprawę wydajności. Przejście do LOAD DATA INFILE doprowadzi do optymalnych rezultatów. Dobre wskazówki dotyczące wydajności można znaleźć na tej stronie dokumentacji mysql .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. mysql SELECT IF instrukcja z OR

  2. usuń wiersz w mojej bazie danych za pomocą php pdo

  3. Wstawianie wielu wierszy w mysql

  4. Jakie są dobre, szybkie i trwałe opcje przechowywania danych klucz->wartość?

  5. Serwer MYSQL zniknął