[英]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.