вторник, 15 ноября 2016 г.

Mysql mass insert

Обычная задача, вставить стопицот миллион записей в mysql.

Так как записи нужно особым образом обрабатывать. то через load data их незагрузишь.

Что приходит в голову первым делом для упрощения вставки, для её ускорения?

Ну prepared statements, окей, делаем:



stmt1, err := db.Prepare("INSERT IGNORE INTO table (a1,a2) VALUES (?,?)")
if err != nil {
  log.Fatalf("mysql: %s", err)
}

for scanner.Scan() {
...
_, err := stmt1.Exec(a1, a2)
if err != nil {
  log.Fatal(err)
}
}
Понятный логичный код. Делал так всю жизнь, привык.

Результат для 64446 записей -  10 минут. Ужас.

Второй вариант, лепим огроменный запросище, клеим его на лету в строку, жрем память, и потом шлем в mysql


sqlStr := "INSERT INTO cats1 (name,url) VALUES "
vals := []interface{}{}
for scanner.Scan() {
..
  sqlStr += "(?,?),"
  vals = append(vals, a1, a2)
}
sqlStr = sqlStr[0 : len(sqlStr)-1]
stmt1, err := db.Prepare(sqlStr)
if err != nil {
  log.Fatalf("mysql: %s ", err)
}
_, err = stmt1.Exec(vals...)
if err != nil {
  log.Fatal(err)
}

Даже выглядит отвратительно, результат для этих же записей - 5 секунд.

Жизнь боль, да.