Laravel - 播种大型 SQL 文件
Posted
技术标签:
【中文标题】Laravel - 播种大型 SQL 文件【英文标题】:Laravel - seeding large SQL file 【发布时间】:2014-11-12 09:53:43 【问题描述】:当我在生产环境中运行我的数据库种子脚本时发生内存耗尽。
下面是我的种子脚本。
class MembershipTableSeeder extends Seeder
public function run()
DB::table('members')->delete();
foreach (range(1, 99) as $days)
Members::create(array('membership_code' => 'test'.$days));
DB::unprepared(file_get_contents(app_path()."/database/seeds/members.sql"));
所以我所做的是在我的种子脚本上添加一个无限制。
ini_set('memory_limit', '-1');
现在的问题是,当我运行脚本时,它会将 SQL 脚本的内容(非常非常大)记录到终端中。
有没有一种在我的数据库种子中运行 SQL 转储且不会消耗太多内存的好方法?我现在做的是手动运行它:
mysql -uuser -p db < script.sql
【问题讨论】:
它包含多少行? 使用 mysql 二进制文件可能是最好的方法。另一种方法是解析并将您的 SQL 拆分为更小的语句并运行多个查询。 只有 16MB 的 sql 文件。 你在安全模式下运行php吗? 只是关于第一部分的建议:Member::create
在循环中 - 不要这样做,而是使用 DB::table(..)->insert(..)
并传递要插入的行数组。它会更快,内存消耗更少。
【参考方案1】:
对于其他更喜欢 Laravel 解决方案的人,我是这样处理的:
/**
* This class is responsible for running the data dump sql.
* It is recommended to update this class instead of creating new ones for new database content dumps.
*/
class DatabaseDumpSeeder extends Seeder
/**
* Run the database seeds.
* @throws \Exception
*/
public function run()
// Note: these dump files must be generated with DELETE (or TRUNCATE) + INSERT statements
$sql = file_get_contents(__DIR__ . '/dumps/dump-20150709.sql');
if (! str_contains($sql, ['DELETE', 'TRUNCATE']))
throw new Exception('Invalid sql file. This will not empty the tables first.');
// split the statements, so DB::statement can execute them.
$statements = array_filter(array_map('trim', explode(';', $sql)));
foreach ($statements as $stmt)
DB::statement($stmt);
【讨论】:
我发现这种方法非常消耗内存,脚本会解析和迭代 SQL 文件,如果文件超过 5000 行怎么办?虽然这只是我的看法。 是的,从 php 运行 sql 脚本非常消耗内存。我强烈建议不要使用数据库播种器来导入生产数据。它仅用于测试/开发数据。 几千行就可以了,没什么大不了的。除此之外,我会考虑自己从 mysql 中播种,或者更好的是通过在控制台上运行命令从 laravel 执行 mysql 加载文件。【参考方案2】:出现问题是因为在使用 Db::unprepared 时,它还会将查询记录到 laravel.log 文件中,在后台执行的操作比您想象的要多得多,从这方面来看,您会耗尽内存。如果您没有运行安全模式,我会坚持执行控制台命令,如下所示:
exec("mysql -u ".\Config::get('database.mysql.user')." -p".\Config::get('database.mysql.password')." ".\Config::get('database.mysql.database')." < script.sql")
【讨论】:
我会尝试更多 Laravel-ish 解决方案,但如果您的文件非常大(常见情况),这将无济于事 感谢您的提示!我关闭了它,因为我的数据库转储太大。 多个.sql
怎么样?【参考方案3】:
使用 Illuminate\Database\Seeder; 类 PostalCodeTableSeeder 扩展播种机 /** * 运行数据库种子。 * * @return 无效 */ 公共函数运行() // ================================================= ============== // 文件路径 -> Project/app/configs/database.php // 获取数据库名称、数据库用户名、数据库密码 // ================================================= ============== $db = \Config::get('database.connections.mysql.database'); $user = \Config::get('database.connections.mysql.username'); $pass = \Config::get('database.connections.mysql.password'); // $this->command->info($db); // $this->command->info($user); // $this->command->info($pass); // 在 php 代码中运行命令行导入 exec("mysql -u".$user."-p".$pass."".$db."< postal_codes.sql"); // postal_codes.sql 在根文件夹中在中创建种子文件“PostalCodeTableSeeder.php” 项目目录/数据库/种子
使用 Illuminate\Database\Seeder; 类 DatabaseSeeder 扩展 Seeder /** * 运行数据库种子。 * * @return 无效 */ 公共函数运行() $this->call(PostalCodeTableSeeder::class); // $this->call(UsersTableSeeder::class);还将类名添加到 Project_directory/database/seed/DatabaseSeeder.php 如下代码
【讨论】:
添加一些解释 ` exec("mysql -u " . $user . " -p" . $pass . " " . $db . " .sql怎么样? 【参考方案4】:我遇到了一个奇怪的问题,即导入大型 SQL 文件作为迁移导致该行未添加到迁移表中。
这就是我修复它的方法。
$path = 'database/data.sql';
$command = "mysql -h".env('DB_HOST')." -u".env('DB_USERNAME')." ".(env('DB_PASSWORD')?"-p'".env('DB_PASSWORD')."'":'')." ".env('DB_DATABASE')." < ".$path;
exec($command);
我注意到对此有类似的答案,但我的方法检查 .env 而不是应用程序配置,支持远程 MySQL 主机,也适用于本地无密码和带有特殊字符的密码会破坏命令行。
【讨论】:
以上是关于Laravel - 播种大型 SQL 文件的主要内容,如果未能解决你的问题,请参考以下文章
我应该在哪里放置包含我在laravel项目层级文件夹中的数据库播种器中使用的记录的.sql文件
我可以合并一个运行 insert into 的 .sql 文件和一个在 2 列上创建虚拟数据的 Laravel 工厂播种器吗?