2016-12-17 14 views
1

大量のデータをmysqlに一括して挿入する必要があります。 500K行ごろ、Laravel 5.3の関係(ハードの部分)とLaravel 5大量挿入との関係

テーブルは自動車、ユーザとuser_vehicleある

平野車の挿入配列は、このようなものになります。

$vehicles = array(); 
foreach ($data as $val) { 
    $temp = array(
     'license_plate' => $val->license_plate, 
     'created_at' => $now, 
     'updated_at' => $now, 
     'state_id' => $activeState, 
     'type_id' => $typeId, 
    ); 

    array_push($vehicles, $temp); 
} 

を私は正常のようなレコードを挿入することができますこれは:

$vehicles = array_chunk($vehicles, 10000); 

foreach ($vehicles as $key => $vehicle) { 
    Vehicle::insert($vehicle); 
} 

すべてのデータを挿入するには数秒かかりますが、今ではそれらにリレーションシップを追加する必要があります。 1台の車両は多くのユーザ(所有者、運転手など)に所属できるので、特定の車両に特定のユーザを付ける必要があります。今

、私は関係を追加しようとしたとき、私はこだわっているのはここです:

$vehicles = array(); 
$vehUsers = array(); 

$users = Users::get(); 

foreach ($data as $val) { 
    // Remap data to right structure 
    $temp = array(
     'license_plate' => $val->license_plate, 
     'created_at' => $now, 
     'updated_at' => $now, 
     'state_id' => $activeState, 
     'type_id' => $typeId, 
    ); 

    // Search for right user (This part is really slow) 
    $userId = $users->where('email', $val->email)->first(); 
    if ($userId) { 
     $userId = $userId->id; 
    } 

    array_push($vehicles, $temp); 

    // Thought that it might help to save them into array for later use 
    array_push($vehUsers, $userId); 
} 

しかし、問題は、私はこの

$vehicles = array_chunk($vehicles, 10000); 

foreach ($vehicles as $key => $vehicle) { 
    Vehicle::insert($vehicle); 
    // Need to attach user here somehow 
} 

のようにそれらを挿入することはできませんそして、私は必要なことであり、 1つの挿入によって1 becouse(私の場合は10K)をバルクでそれらを実行することは、私は、インサート車一括することができます

// Insert them and relations one by one and it will take years 
foreach ($vehicles as $key => $vehicle) { 
    $veh = Vehicle::insert($vehicle); 
    $veh->users()->attach($vehUsers[$key]); 
} 

どのように時間がかかりすぎます彼らの関係は?

EDIT:遅い部分はDBクエリを実行しています。 PHPで項目をループするのを10〜20秒待つことができます。

答えて

1

まず、すべてのユーザーを読み込みます。しかし、唯一のidemailを選択:

$users = User::pluck('email', 'id')->toArray(); 

これは[id => email]構造を持つ配列を作成します。

その後、あなたは追加のクエリを実行せずに、この配列で作業できるようになります:

$userId = $users[$email]; 

はその後vehicle_userピボットテーブルにbigintタイプのid列を追加します。このテーブルに対して別のチャンク配列を作成し、attach()メソッドを使用する代わりにリレーションの一括挿入を使用します。

+0

コードの最初の部分をありがとう。それは本当に物事をより速く=)そして直接DB_:insert(bulk_data)を使ってvehicle_userに追加します。最初の一括挿入から車両IDを取得する方法を把握していただけです。 –

0

まず、あなたが次のテクニックは、あなたがループすることを理解してください$data(これは本当に本当に大きいです)何度も何度も繰り返します。どうして? ...

  1. 一時変数を作成するための最初のforループ。
  2. 次に、チャンクされたデータを挿入する2番目のforループ。
  3. 入力と同じ電子メールでの検索ユーザーのためのループのための第三
  4. し、その同じユーザの車を選択し、あなたは、単にあなたのことを成し遂げることができるすべてのために一つだけのループを作ることで$user->vehicles()->sync([...Vehicle Ids...]);

でそれを同期取り付け

foreach($data as $key => $vehicle) { 
    $vehicle = Vehicle::create([ 
         'license_plate' => $vehicle->license_plate, 
         'state_id' => $activeState, 
         'type_id' => $typeId, 
        ]); 

    $user = User::where('email', $vehicle->email)->first(); 

    $vehicle->users()->attach([$user->id]); 
} 

によってBelongsToMany方法が本当に独自のモデルを持っていませんのでご了承くださいが、そのような/ 1時間の場合のために...あなたは試してみて、ピボットテーブルモデルを作成し、その後、同様にあなたのクエリを処理することができます。しかし、もう一度、Vehicle::where('license_plate', $val->license_plate)のようなものが依然として必要かもしれません....それは再び役に立たないです。

注:1つのforループで3つのクエリを実行できます。複数のクエリを持つループの場合は3です。私は間違いなく最初のものを好むでしょう

+0

** 1)最初のループを実行すると約5-10秒かかります。 ** 2)**チャンクデータの挿入には数秒しかかかりません。 DBクエリの実行は実際には遅いです。ループを挿入すると約20分かかります。変数にループする前にすべてのユーザーを保存するほうが、各サークルごとにDBから要求するよりもずっと速くなります。私はここで生のSQLを使用する必要があると思う:/ –

+0

@ MargusKevinあなたは私の答えを試しましたか? – prateekkathal

+1

はい、それは15分間実行され、タイムアウトで終了しました –

関連する問題