【问题标题】:How to insert big data on the laravel?如何在 laravel 上插入大数据?
【发布时间】:2018-12-31 10:27:10
【问题描述】:

我正在使用 laravel 5.6

我插入大数据的脚本是这样的:

...
$insert_data = [];
foreach ($json['value'] as $value) {
    $posting_date = Carbon::parse($value['Posting_Date']);
    $posting_date = $posting_date->format('Y-m-d');
    $data = [
        'item_no'                   => $value['Item_No'],
        'entry_no'                  => $value['Entry_No'], 
        'document_no'               => $value['Document_No'],
        'posting_date'              => $posting_date,
        ....
    ];
    $insert_data[] = $data;
}
\DB::table('items_details')->insert($insert_data);

我尝试在脚本中插入 100 条记录,它可以工作。成功插入数据

但是如果我尝试用脚本插入 50000 条记录,它会变得非常慢。我已经等了大约 10 分钟,但它没有工作。存在这样的错误:

504 Gateway Time-out

我该如何解决这个问题?

【问题讨论】:

  • 你可以使用 Laravel 的分块函数来分块数据。也许这篇文章会对你有所帮助insert big data
  • 你也可以使用 Laravel 队列系统,每次插入创建 50,000 个作业。但是如果你坚持大量发送,你需要增加 PHP 超时时间(你会想 google 一下你的服务器堆栈是什么)
  • 是的,在这种情况下,chunk 不会真正帮助您。 chunk 将有助于解决内存使用问题,但不适用于您的应用程序运行时间过长。就像 Rob 建议的那样,研究使用队列并为每个单独的项目创建一个作业。然后你可以运行一堆工人来为你处理数据。
  • @Dwight 我仍然很困惑。尝试用详细的答案(用脚本)回答这个问题
  • @Rob Fonseca 我仍然很困惑。尝试用详细的答案(用脚本)回答这个问题

标签: laravel laravel-5 insert bigdata laravel-5.6


【解决方案1】:

如前所述,如果是时间执行问题,在这种情况下,块不会真正帮助您。我认为您尝试使用的批量插入无法处理那么多数据,所以我看到了 2 个选项:

1 - 重新组织你的代码以正确使用块,这看起来像这样:

$insert_data = [];

foreach ($json['value'] as $value) {
    $posting_date = Carbon::parse($value['Posting_Date']);

    $posting_date = $posting_date->format('Y-m-d');

    $data = [
        'item_no'                   => $value['Item_No'],
        'entry_no'                  => $value['Entry_No'], 
        'document_no'               => $value['Document_No'],
        'posting_date'              => $posting_date,
        ....
    ];

    $insert_data[] = $data;
}

$insert_data = collect($insert_data); // Make a collection to use the chunk method

// it will chunk the dataset in smaller collections containing 500 values each. 
// Play with the value to get best result
$chunks = $insert_data->chunk(500);

foreach ($chunks as $chunk)
{
   \DB::table('items_details')->insert($chunk->toArray());
}

这样您的批量插入将包含更少的数据,并且能够以相当快速的方式处理它。

2 - 如果您的主机支持运行时重载,您可以在代码开始执行之前添加一个指令:

ini_set('max_execution_time', 120 ) ; // time in seconds

$insert_data = [];

foreach ($json['value'] as $value)
{
   ...
}

要了解更多信息,请转到官方docs

【讨论】:

  • 使用第二个选项,您仍然可以使用块来避免大块块
  • 感谢您的回答。我会试试看。请用块更新你的答案。所以存在一些选择
  • 我试过你的脚本。存在这样的错误:Argument 1 passed to Illuminate\Database\Query\Builder::insert() must be of the type array, object given
  • @SuccessMan 只需使用->toArray() 方法
  • 已更新 ^^。检查块
【解决方案2】:

使用数组然后将其转换为集合是没有意义的。

我们可以摆脱数组。

$insert_data = collect();

foreach ($json['value'] as $value) {
    $posting_date = Carbon::parse($value['Posting_Date']);

    $posting_date = $posting_date->format('Y-m-d');

    $insert_data->push([
        'item_no'                   => $value['Item_No'],
        'entry_no'                  => $value['Entry_No'], 
        'document_no'               => $value['Document_No'],
        'posting_date'              => $posting_date,
        ....
    ]);
}

foreach ($insert_data->chunk(500) as $chunk)
{
   \DB::table('items_details')->insert($chunk->toArray());
}

【讨论】:

    【解决方案3】:

    这里是非常好的非常快速的插入数据解决方案

    $no_of_data = 1000000;
    $test_data = array();
    for ($i = 0; $i < $no_of_data; $i++){
        $test_data[$i]['number'] = "1234567890";
        $test_data[$i]['message'] = "Test Data";
        $test_data[$i]['status'] = "Delivered";
    }
    $chunk_data = array_chunk($test_data, 1000);
    if (isset($chunk_data) && !empty($chunk_data)) {
       foreach ($chunk_data as $chunk_data_val) {
        DB::table('messages')->insert($chunk_data_val);
      }
    }
    

    【讨论】:

      【解决方案4】:

      我使用下面的代码检查了 11000 行的更新或插入数据。希望对你有用。

      $insert_data = [];
      for ($i=0; $i < 11000; $i++) { 
          $data = [
              'id' =>'user_'.$i,
              'fullname' => 'Pixs Nguyen',
              'username' => 'abc@gmail.com',
              'timestamp' => '2020-03-23 08:12:00',
          ];
          $insert_data[] = $data;
      }
      
      $insert_data = collect($insert_data); // Make a collection to use the chunk method
      
      // it will chunk the dataset in smaller collections containing 500 values each. 
      // Play with the value to get best result
      $accounts = $insert_data->chunk(500);
      // In the case of updating or inserting you will take about 35 seconds to execute the code below
      for ($i=0; $i < count($accounts); $i++) { 
          foreach ($accounts[$i] as $key => $account)
          {
              DB::table('yourTable')->updateOrInsert(['id'=>$account['id']],$account);
          }
      }
      // In the case of inserting you only take about 0.35 seconds to execute the code below
      foreach ($accounts as $key => $account)
      {
          DB::table('yourTable')->insert($account->toArray());
      }
      

      【讨论】:

        猜你喜欢
        • 2018-02-13
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 2016-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多