Laravel-Excel 2, вставляйте данные быстрее

Это основной код метода, который я использую для импорта файла Excel (с использованием Maatwebsite Laravel-Excel 2) в мою базу данных:

$data = Excel::selectSheetsByIndex(0)->load($file, function($reader) {})->get()->toArray();
DB::beginTransaction();
try {
    foreach ($data as $key => $value) {
        $med= trim($value["med"]);
        $serial = trim($value["nro.seriemedidor"]);

        DB::table('medidores')->insert([
            "med" => $med,
            "serial_number" => $serial
        ]);
    }
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
    return redirect()->route('myroute')->withErrors("Some error message");
}

Это отлично работает, когда у меня «мало» данных (скажем, менее 5000 строк в файле Excel). Но мне нужно работать с большим файлом Excel, который содержит около 1,4 миллиона строк, разделенных более чем на 1 лист. Как я могу сделать мой метод более быстрым? Есть подсказка?

РЕДАКТИРОВАТЬ: Я отредактирую вопрос кодом, который был по ссылке одного из комментариев ответа:

$data = Excel::selectSheetsByIndex(0)->load($file, function($reader) {})->get()->toArray();
DB::beginTransaction();
try {
  $bulk_data = [];
  foreach ($data as $key => $value) {
    $med= trim($value["med"]);
    $serial = trim($value["nro.seriemedidor"]);
    $bulk_data[] = ["med" => $med,"serial_number" => $serial] ;
  }
  $collection = collect($bulk_data);   //turn data into collection
  $chunks = $collection->chunk(100); //split into chunk of 100's
  $chunks->toArray(); //convert chunk to array
 //loop through chunks:
 foreach($chunks as $chunk)
 {
   DB::table('medidores')->insert($chunk->toArray());
 }
  DB::commit();
} catch (\Exception $e) {
  DB::rollback();
  return redirect()->route('myroute')->withErrors("Some error message");
}

У меня сработала штука с кусками.


person pmiranda    schedule 14.05.2018    source источник


Ответы (1)


Да, вы можете, вместо выполнения X (количество запросов к базе данных) * N (количество листов) попробуйте выполнить простую массовую вставку, которая будет стоить вам только сложности цикла по сохранению данных, сохраняющих X * N запросов к базе данных, вот пример:

$data = Excel::selectSheetsByIndex(0)->load($file, function($reader) {})->get()->toArray();
DB::beginTransaction();
try {
  $bulk_data = [];
  foreach ($data as $key => $value) {
     $med= trim($value["med"]);
     $serial = trim($value["nro.seriemedidor"]);
     $bulk_data[] = ["med" => $med,"serial_number" => $serial] ;
  }
  DB::table('medidores')->insert($bulk_data);
  DB::commit();
} catch (\Exception $e) {
  DB::rollback();
  return redirect()->route('myroute')->withErrors("Some error message");
}

Вы можете обратиться к этому ответу для получения дополнительных сведений о запросах db: https://stackoverflow.com/a/1793209/8008456

person Salamov    schedule 14.05.2018
comment
Ммм, я знаю, что в этом есть смысл, но я провожу тест в своем коде, и с моим кодом вставка 5000 строк занимает 9 секунд. С массивом в конце это занимает 14 секунд ... Я могу снять это на видео, если вы мне не верите. - person pmiranda; 14.05.2018
comment
И на самом деле я тестировал в MariaDB и PostgreSQL в двух разных проектах, с Laravel 5.4 и 5.6. Всегда было быстрее со вставками внутри foreach, я не знаю почему. - person pmiranda; 16.05.2018
comment
Отлично! Я тестировал другую вставку, которая у меня есть, и это заняло 30 секунд вместо 45. 50% быстрее. Я попробую с другим. - person pmiranda; 17.05.2018
comment
Похоже, вам нужно распределить сложность между запросами к базе данных и внутренним циклом по объемным данным, при вставке (без цикла по основным данным) попробуйте увеличить / уменьшить размер блоков и посмотреть, что произойдет. - person Salamov; 17.05.2018
comment
Я тестировал фрагменты по 5, 100, 500, он не слишком сильно меняется, всегда требуется ~ 30 секунд для завершения вставки (3649 строк, 12 столбцов). Но для меня это здорово. - person pmiranda; 17.05.2018
comment
Попробуйте использовать этот пакет всякий раз, когда вы свободны github.com/rap2hpoutre/fast-excel#benchmarks Это оболочка над пакетом Spout, который, как считается, дает более лучшие результаты, я еще не пробовал, но тесты кажутся интересными. Изменить: (Упоминается, чтобы не доверять их тестам LOL) - person Salamov; 17.05.2018