使用 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中生成数据(内存量很大,并且在大循环中使用时没有被垃圾回收器正确清除。

我同意 Mkrtchyan @Rob上面添加的卡盘处理,但由于这是 Laravel,我会建议使用工厂设施的更优雅的解决方案。

您可以创建一个特定的模型工厂(在Laravel 5.3中,这应该放在数据库/工厂/中(,例如:

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

使用种子工厂的原因是,它允许您在设置变量等方面具有更大的灵活性。有关这方面的文档,您可以查阅有关 dB 播种的 Laravel文档

现在,由于您正在处理大量记录,因此实现一个有助于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 工厂和集合分块,插入 50.000 行 ~1 分钟

使用一个简单的数组和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 设置的情况下运行它......

享受。。