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(..)-&gt;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】:

在中创建种子文件“PostalCodeTableSeeder.php” 项目目录/数据库/种子

使用 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."&lt postal_codes.sql"); // postal_codes.sql 在根文件夹中

还将类名添加到 Project_directory/database/seed/DatabaseSeeder.php 如下代码

使用 Illuminate\Database\Seeder; 类 DatabaseSeeder 扩展 Seeder /** * 运行数据库种子。 * * @return 无效 */ 公共函数运行() $this->call(PostalCodeTableSeeder::class); // $this->call(UsersTableSeeder::class);

【讨论】:

添加一些解释 ` 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 工厂播种器吗?

播种时LARAVEL 5.4 SQL“找不到列”

Laravel 4 db 种子特定播种器文件

Laravel 路由问题:自动重定向到根文件夹

Laravel 5:如何将播种器类添加到自动加载?