You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何DB::transaction()内代码执行速度远快于非事务场景?

问题描述

我有一个数据库seeder,需要向数据库中填充1万+条数据。当未使用DB::transaction包裹代码运行时,while循环执行耗时超过5分钟;而将代码包裹在DB::transaction中运行时,耗时不到1分钟,性能提升超5倍。请问这一性能提升的来源是什么?

事务包裹写法

DB::transaction(function () {
    $fp = gzopen(database_path() . '/seeders/cars.json.gz', 'r');
    $i = 0;
    
    while ($json_text = fgets($fp)) {
        $json = json_decode($json_text, true);

        DB::table('cars')->insert([
            'full_name' => $json['full_name'],
            'slug_name' => $json['slug_name'],
            'year' => $json['Ano'],
            'model' => array_key_exists('model', $json) ? $json['model'] : null,
            'name' => $json['name'],
            'brand_id' => Brand::where('name', $json['brand'])->first()->id,
            'content' => $json_text,
            'created_at' => new \Datetime(),
            'updated_at' => new \Datetime()
        ]);
        
        echo "Inserted " . ++$i . " cars\n";
    }
    
    fclose($fp);
});

未使用事务包裹写法

$fp = gzopen(database_path() . '/seeders/cars.json.gz', 'r');
$i = 0;
    
while ($json_text = fgets($fp)) {
    $json = json_decode($json_text, true);
    
    DB::table('cars')->insert([
        'full_name' => $json['full_name'],
        'slug_name' => $json['slug_name'],
        'year' => $json['Ano'],
        'model' => array_key_exists('model', $json) ? $json['model'] : null,
        'name' => $json['name'],
        'brand_id' => Brand::where('name', $json['brand'])->first()->id,
        'content' => $json_text,
        'created_at' => new \Datetime(),
        'updated_at' => new \Datetime()
    ]);

    echo "Inserted " . ++$i . " cars\n";
}
    
fclose($fp);
性能提升的核心来源
  • 自动提交模式的重复IO开销:MySQL等绝大多数关系型数据库默认开启*自动提交(autocommit)*模式,没有手动声明事务时,每一条INSERT语句都会被判定为独立事务,执行完成后立刻触发持久化提交流程。1万条数据就会产生1万次独立提交:写事务日志、强制刷盘、同步事务状态、释放锁,零散的磁盘随机IO成本极高。
  • 批量提交的IO合并收益:用DB::transaction包裹后,所有INSERT操作都属于同一个事务,只会在代码块执行完成后做1次最终提交。执行期间所有数据修改先在内存中完成,事务日志可以批量顺序刷盘,把1万次零散IO合并成1次批量IO,这是性能提升的最核心原因。
  • 锁管理开销降低:非事务模式下每条插入都要独立申请行锁、提交后立刻释放,反复加锁释放锁本身有不小的CPU调度开销;单事务模式下锁只需要在最终提交时统一释放,省去了大量重复的锁管理操作。
  • 事务日志写入量减少:每次事务提交都要写入对应的日志元数据、做持久化校验,1万次小事务的日志写入总量、磁盘fsync调用次数远高于1次大事务,这个差距在机械硬盘场景下会被进一步放大。

补充提示:如果单事务操作的数据量达到百万级以上,可能出现undo log过长、内存占用过高的问题,万级数据量用单事务包裹批量写入是完全安全的,也是行业通用的批量写入优化方案。

内容的提问来源于stack exchange,提问作者Kos-Mos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 20:12:27