簡體   English   中英

使用 Laravel DB Seed 插入 100 萬條記錄

[英]Insert 1 million records using Laravel DB Seed

我正在使用 faker 來獲取虛擬數據並嘗試添加 100 萬條記錄。 不知何故,我只能達到大約 100000 行,以下是我的代碼

$no_of_rows = 1000000;

for( $i=1; $i <= $no_of_rows; $i++ ){
        $user_data[] = [
            'status' => 'ACTIVE',
            'username' => $faker->userName,
            'email' => $faker->email,
            'password' => $password,
            'firstname' => $faker->firstName,
            'surname' => $faker->lastName,
            'mobilenumber' => $faker->phoneNumber,
            'confirmed' => (int)$faker->boolean(50),
            'gender' => $faker->boolean(50) ? 'MALE' : 'FEMALE',
            'dob' => $faker->date(),
            'address_line_1' => $faker->address,
            'address_line_2' => '',
            'post_code' => $faker->postcode,
        ];


}

User::insert($user_data);

我收到以下錯誤消息

PHP Fatal error:  Allowed memory size of 1073741824 bytes exhausted

我已經設置了ini_set('memory_limit', '1024M');

有什么有用的想法或解決方案嗎?

這個問題的核心問題是Faker lib 實例(通常用於在 Laravel 中生成數據)內存很重,並且在大循環中使用時垃圾收集器無法正確清除它。

我同意 @ Rob Mkrtchyan上面添加的卡盤處理,但由於這是 Laravel,我建議使用工廠設施提供更優雅的解決方案。

您可以創建一個特定的模型工廠(在 Laravel 5.3 中,這應該放在 database/factories/ 中),例如:

$factory->define(Tests::class, function (Faker\Generator $faker) {
    return [
        'status' => 'ACTIVE',
        'username' => $faker->userName,
        'email' => $faker->email,
        'password' => bcrypt('secret'),
        'firstname' => $faker->firstName,
        'surname' => $faker->lastName,
        'mobilenumber' => $faker->phoneNumber,
        'confirmed' => (int)$faker->boolean(50),
        'gender' => $faker->boolean(50) ? 'MALE' : 'FEMALE',
        'dob' => $faker->date(),
        'address_line_1' => $faker->address,
        'address_line_2' => '',
        'post_code' => $faker->postcode,
    ];
});

然后在您的 dB 播種器類中運行工廠是一件簡單的事情。 請注意,數字 200 表示要創建的種子數據條目的數量。

factory(Tests::class, 200)
    ->create();

使用種子工廠的原因是它允許您在設置變量等方面有更大的靈活性。有關這方面的文檔,您可以查閱Laravel 文檔關於 dB 播種

現在,由於您正在處理大量記錄,因此實現一個有助於 php 垃圾收集的分塊解決方案是微不足道的。 例如:

for ($i=0; $i < 5000; $i++) {
    factory(Tests::class, 200)
        ->create();
}

我做了一個快速測試,在此配置中,您的腳本內存使用量應該在 12 - 15mb 左右(當然取決於其他系統因素),無論創建的數據條目如何。

foreach循環中設置的變量永遠不會被使用,所以如果 foreach 循環的唯一目的是添加一百萬條記錄,您可以取消 foreach 並使用類似的東西嗎? 這樣,用於填充數據庫的數組會在每次迭代時重新聲明,而不是添加越來越多的條目。

$no_of_rows = 1000000;

for( $i=0; $i < $no_of_rows; $i++ ){
    $user_data = array(
        'status' => 'ACTIVE',
        'username' => $faker->userName,
        'email' => $faker->email,
        'password' => $password,
        'firstname' => $faker->firstName,
        'surname' => $faker->lastName,
        'mobilenumber' => $faker->phoneNumber,
        'confirmed' => (int)$faker->boolean(50),
        'gender' => $faker->boolean(50) ? 'MALE' : 'FEMALE',
        'dob' => $faker->date(),
        'address_line_1' => $faker->address,
        'address_line_2' => '',
        'post_code' => $faker->postcode,
    );

    User::insert( $user_data );
    $user_data=null;
}

根據您的最后評論,我可以看到為什么使用塊 - 在發布答案之前無法知道 sql 的語法,所以也許這可能更合適?

$no_of_rows = 1000000;
$range=range( 1, $no_of_rows );
$chunksize=1000;

foreach( array_chunk( $range, $chunksize ) as $chunk ){
    $user_data = array();/* array is re-initialised each major iteration */
    foreach( $chunk as $i ){
        $user_data[] = array(
            'status' => 'ACTIVE',
            'username' => $faker->userName,
            'email' => $faker->email,
            'password' => $password,
            'firstname' => $faker->firstName,
            'surname' => $faker->lastName,
            'mobilenumber' => $faker->phoneNumber,
            'confirmed' => (int)$faker->boolean(50),
            'gender' => $faker->boolean(50) ? 'MALE' : 'FEMALE',
            'dob' => $faker->date(),
            'address_line_1' => $faker->address,
            'address_line_2' => '',
            'post_code' => $faker->postcode
        );      
    }
    User::insert( $user_data );
}

您好:這里是非常好的非常快速的插入數據解決方案

$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);
  }
}

我試圖插入 1600 萬條記錄。 我找到了最好和快速的解決方案。

使用 Laravel 9 工廠和集合分塊,大約 1 分鍾插入了 50.000 行。

使用一個簡單的數組和array_chunk()我得到了大約 30 秒的 50.000 行。

所有 16.000.000 行都在 40 分鍾內插入 :)

use Faker\Generator;
use Illuminate\Container\Container;
        $accounts = User::query()->pluck('id');
        $faker = Container::getInstance()->make(Generator::class);
        $ownProductId = $faker->regexify('[LD0-9]{1}[A-Z0-9]{9}');
        $data = [];

        for($i=0; $i< 320; $i++) {
            for($v=0; $v< 50000; $v++) {
                $data[] = [
                    'createdAt'       => (int)date('U'),
                    'productId'       => $ownProductId,
                    'title'           => $faker->sentence(3),
                    'imageUrl'        => '',
                    'User_id'         => $accounts->random(),
                    'productIds'      => implode(',', $this->generateFakeProductIds($ownProductId)),
                    'parentProductId' => $faker->regexify('[LD0-9]{1}[A-Z0-9]{9}'),
                    'status' => $faker->randomElement(StatusesEnum::cases()),
                    'searchType'      => $faker->randomElement(SearchTypesEnum::cases()),
                    'url'             => Str::random(50),
                    'marketplace'     => $faker->randomElement(array_keys(MarketplacesConfigService::CONFIGS)),
                ];

            }

            $chunks = array_chunk($data, 5000);
            foreach ($chunks as $chunk) {
                TestModel::query()->insert($chunk);
            }
        }

你好:這是一個很好的解決方案

public function run(){
    for($j = 1; $j < 1000; $j++){
        for($i = 0; $i < 1000; $i++){
             $user_data[] = [
                 'status' => 'ACTIVE',
                 'username' => $faker->userName,
                 'email' => $faker->email,
                 'password' => $password,
                 'firstname' => $faker->firstName,
                 'surname' => $faker->lastName,
                 'mobilenumber' => $faker->phoneNumber,
                 'confirmed' => (int)$faker->boolean(50),
                 'gender' => $faker->boolean(50) ? 'MALE' : 'FEMALE',
                 'dob' => $faker->date(),
                 'address_line_1' => $faker->address,
                 'address_line_2' => '',
                 'post_code' => $faker->postcode,
             ];
        }

        User::insert($user_data);
    }
}

這段代碼在內存中只使用了 1000 個長度的數組……你可以在不更改任何默認 php 設置的情況下運行它……

享受,..

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM