我有一个包含超过 30,000 条记录的文件,另一个包含 41,000 条记录。是否有使用 laravel 4 的db:seed
命令播种的最佳案例研究?一种使插入更迅速的方法。
谢谢您的帮助。
不要害怕,40K 行的表有点小。我有一个 100 万行的表,种子很顺利,我只需要在做之前添加这个:
DB::disableQueryLog();
在禁用它之前,Laravel 浪费了我所有的 PHP 内存限制,不管我给了多少。
我使用 .txt 文件读取数据fgets()
,以编程方式构建数组并执行:
DB::table($table)->insert($row);
一个接一个,可能特别慢。
我的数据库服务器是 PostgreSQL,插入需要大约 1.5 小时才能完成,可能是因为我使用的 VM 内存不足。这些天我会在一台更好的机器上做一个基准测试。
我遇到了同样的问题,经过 2 天的头痛,我终于可以在不到 30 秒的时间内编写脚本来播种 42K 条目!
你问如何?
此方法假定您有一个包含一些条目的数据库(在我的情况下是 42k 条目),并且您希望将其导入其他数据库。将数据库导出为带有标题名称的 CSV 文件并将文件放入项目的公共文件夹中,然后您可以解析文件并通过播种器将所有条目一一插入新数据库中。
所以你的播种机看起来像这样:
<?php
use Illuminate\Database\Seeder;
class {TableName}TableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$row = 1;
if (($handle = fopen(base_path("public/name_of_your_csv_import.csv"), "r")) !== false) {
while (($data = fgetcsv($handle, 0, ",")) !== false) {
if ($row === 1) {
$row++;
continue;
}
$row++;
$dbData = [
'col1' => '"'.$data[0].'"',
'col2' => '"'.$data[1].'"',
'col3' => '"'.$data[2].'"',
so on...how many columns you have
];
$colNames = array_keys($dbData);
$createQuery = 'INSERT INTO locations ('.implode(',', $colNames).') VALUES ('.implode(',', $dbData).')';
DB::statement($createQuery, $data);
$this->command->info($row);
}
fclose($handle);
}
}
}
简单易行:)
如果您可以修改 PHP 的设置并为特定脚本分配较大的大小,那么此方法也可以正常工作。
那么基本上你需要专注于三个主要步骤:
insert()
一次创建 1K 的块。因此,如果我在播种机中结合上述所有步骤,您的播种机将如下所示:
<?php
use Illuminate\Database\Seeder;
class {TableName}TableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
ini_set('memory_limit', '512M');//allocate memory
DB::disableQueryLog();//disable log
//create chunks
$data = [
[
[
'col1'=>1,
'col2'=>1,
'col3'=>1,
'col4'=>1,
'col5'=>1
],
[
'col1'=>1,
'col2'=>1,
'col3'=>1,
'col4'=>1,
'col5'=>1
],
so on..until 1000 entries
],
[
[
'col1'=>1,
'col2'=>1,
'col3'=>1,
'col4'=>1,
'col5'=>1
],
[
'col1'=>1,
'col2'=>1,
'col3'=>1,
'col4'=>1,
'col5'=>1
],
so on..until 1000 entries
],
so on...until how many entries you have, i had 42000
]
//iterate and insert
foreach ($data as $key => $d) {
DB::table('locations')->insert($d);
$this->command->info($key);//gives you an idea where your iterator is in command line, best feeling in the world to see it rising if you ask me :D
}
}
}
瞧,你很高兴:)
我希望它有帮助
我正在从不同的数据库迁移,我不得不使用原始 sql(从外部文件加载)和批量插入语句(我通过 navicat 导出结构,它可以选择每 250KiB 分解一次插入语句)。例如:
$sqlStatements = array(
"INSERT INTO `users` (`name`, `email`)
VALUES
('John Doe','john.doe@gmail.com'),.....
('Jane Doe','jane.doe@gmail.com')",
"INSERT INTO `users` (`name`, `email`)
VALUES
('John Doe2','john.doe2@gmail.com'),.....
('Jane Doe2','jane.doe2@gmail.com')"
);
然后我遍历插入语句并使用执行
DB::statement($sql).
我无法一次插入一行。我确信有更好的替代方案,但这至少可以让我将它保留在 Laravel 的迁移/播种中。
我今天遇到了同样的问题。禁用查询日志是不够的。看起来一个事件也被解雇了。
DB::disableQueryLog();
// 做插入
// 重置事件以释放内存。
DB::setEventDispatcher(new Illuminate\Events\Dispatcher());