新闻中心

Yii2中JSON数据批量导入MySQL的性能优化实践

2025-11-06
浏览次数:
返回列表

Yii2中JSON数据批量导入MySQL的性能优化实践

本文深入探讨了在yii2框架下从json文件批量导入数据到mysql时遇到的性能瓶颈及优化策略。通过对比activerecord的s*e()方法与db命令的insert()及batchinsert(),并结合预加载关联数据,显著提升了导入效率。文章提供了详细的代码示例和注意事项,旨在帮助开发者高效处理大规模数据导入任务。

引言:理解批量数据导入的性能瓶颈

在Web应用开发中,尤其是在数据同步或初始化场景下,我们常需要将大量数据从文件(如JSON)导入到数据库。然而,如果不采用正确的策略,这一过程可能会非常耗时。原始代码中,开发者使用Yii2 ActiveRecord的s*e()方法在循环中逐条插入数据,导致了显著的性能下降。例如,导入数百条记录的时间会从几秒迅速增长到几十秒甚至更长,对于数万甚至百万级别的数据量,这种方法是不可接受的。

s*e()方法虽然方便,但它为每个模型实例执行了多项操作:实例化模型、数据验证、触发事件回调、以及最终执行一条独立的SQL INSERT 或 UPDATE 语句。当这些操作在循环中针对大量记录重复执行时,其累积的开销(包括PHP层面的处理和与数据库的多次往返通信)将成为严重的性能瓶颈。

考虑以下原始实现的核心逻辑:

foreach ($products as $product) {
    $item = new Product_dub();
    // ... 赋值属性 ...
    $category = Category_dub::findOne(['id_1c_category' => $product->category_id]); // 每次循环查询
    $brand = Brands_dub::findOne(['id_1c_brand' => $product->brand_id]); // 每次循环查询
    // ... 赋值关联ID ...
    if (!$item->s*e()) { // 每次循环执行一次INSERT
        // ... 错误处理 ...
    }
}

从上述代码可以看出,除了每次循环进行两次数据库查询来获取category和brand之外,最主要的性能消耗在于$item->s*e()。即使移除了findOne()查询,s*e()本身的开销依然巨大。

优化策略一:从ActiveRecord s*e() 到DB命令 insert()

解决s*e()性能问题的首要步骤是绕过ActiveRecord的全部生命周期,直接使用Yii2的数据库命令执行INSERT操作。Yii2的Yii::$app->db->createCommand()->insert()方法允许我们直接构建并执行SQL插入语句,极大地减少了框架层面的开销。

通过将$item->s*e()替换为insert()命令,性能得到了显著提升。例如,在测试中,1107行数据导入时间从最初的数分钟缩短到约40秒。

以下是使用insert()命令进行优化的示例:

foreach ($products as $product) {
    Yii::$app->db->createCommand()->insert('product_dub', [
        'id_1c_product' => $product->id,
        // ... 其他属性 ...
        'category_id' => $categoryMap[$product->category_id] ?? '0', // 假设categoryMap已预加载
        'brand_id' => $brandMap[$product->brand_id] ?? 'No brand',   // 假设brandMap已预加载
        // ...
    ])->execute();
}

这种方法虽然仍是循环中逐条插入,但每次循环仅执行一次SQL INSERT 命令,避免了ActiveRecord的验证、事件等额外处理,从而显著提高了效率。

网趣网上购物系统HTML静态版 网趣网上购物系统HTML静态版

网趣购物系统静态版支持网站一键静态生成,采用动态进度条模式生成静态,生成过程更加清晰明确,商品管理上增加淘宝数据包导入功能,与淘宝数据同步更新!采用领先的AJAX+XML相融技术,速度更快更高效!系统进行了大量的实用性更新,如优化核心算法、增加商品图片批量上传、谷歌地图浏览插入等,静态版独特的生成算法技术使静态生成过程可随意掌控,从而可以大大减轻服务器的负担,结合多种强大的SEO优化方式于一体,使

网趣网上购物系统HTML静态版 0 查看详情 网趣网上购物系统HTML静态版

优化策略二:预加载关联数据以减少查询次数

在原始代码中,Category_dub::findOne()和Brands_dub::findOne()在每次循环中都会执行一次数据库查询,以根据外部ID查找内部ID。对于N条记录,这将导致2N次额外的数据库查询,这就是典型的N+1查询问题,进一步拖慢了导入速度。

为了消除这些重复查询,我们应该在导入循环开始之前,一次性地从数据库中加载所有必要的关联数据,并将其存储在内存中的映射(Map)结构中。这样,在循环内部,我们只需进行内存查找,而非数据库查询。

以下是预加载分类和品牌数据的示例:

$categoryMap = Category_dub::find()->select(['id', 'id_1c_category'])->indexBy('id_1c_category')->column();
$brandMap = Brands_dub::find()->select(['id', 'id_1c_brand'])->indexBy('id_1c_brand')->column();

foreach ($products as $product) {
    Yii::$app->db->createCommand()->insert('product_dub', [
        'id_1c_product' => $product->id,
        'category_id' => $categoryMap[$product->category_id] ?? '0', // 从内存映射中获取
        'title' => $product->title,
        'brand_id' => $brandMap[$product->brand_id] ?? 'No brand',   // 从内存映射中获取
        'content1' => $product->content1,
        'content2' => $product->content2,
        'content3' => $product->content3,
        'link_order' => $product->link_order,
        'img' => $product->img ?? 'no-image.png',
        'in_stock' => $product->in_stock ? 1 : 0,
        'is_popular' => $product->is_popular ? 1 : 0,
    ])->execute();
}

通过结合insert()命令和预加载关联数据,我们可以看到一个完整的、大幅优化后的导入逻辑。

更进一步的性能提升:使用 batchInsert()

尽管insert()命令比s*e()快得多,但它仍然是循环中逐条执行SQL语句。对于处理数万甚至百万级别的数据,最佳实践是使用Yii2提供的batchInsert()方法。batchInsert()能够生成一条包含多行数据的INSERT SQL语句,一次性将多条记录发送到数据库,从而显著减少了与数据库的通信次数,进一步提升了性能。

batchInsert()方法的参数包括表名、列名数组和值数组(每个元素代表一行数据)。

public function importProductFile($file, $return = true)
{    
    $products = json_decode($file, true); // 解码为关联数组更方便
    $dubTableName = Product::tableName() . "_dub";
    $start = time();

    if ($this->db->createDuplicateTable(Product::tableName(), $dubTableName)) {
        $categoryMap = Category_dub::find()->select(['id', 'id_1c_category'])->indexBy('id_1c_category')->column();
        $brandMap = Brands_dub::find()->select(['id', 'id_1c_brand'])->indexBy('id_1c_brand')->column();

        $rows = [];
        foreach ($products as $product) {
            $rows[] = [
                'id_1c_product' => $product['id'],
                'category_id' => $categoryMap[$product['category_id']] ?? '0',
                'title' => $product['title'],
                'brand_id' => $brandMap[$product['brand_id']] ?? 'No brand',
                'content1' => $product['content1'],
                'content2' => $product['content2'],
                'content3' => $product['content3'],
                'link_order' => $product['link_order'],
                'img' => $product['img'] ?? 'no-image.png',
                'in_stock' => $product['in_stock'] ? 1 : 0,
                'is_popular' => $product['is_popular'] ? 1 : 0,
            ];
        }

        // 批量插入数据
        if (!empty($rows)) {
            Yii::$app->db->createCommand()->batchInsert('product_dub', array_keys($rows[0]), $rows)->execute();
        }
    }

    $finish = time();
    $res = $finish - $start . "sec. ";

    if ($return) {
        echo $res;
        Answer::success();
    }
}

高级优化与注意事项

除了上述代码层面的优化,还有一些其他因素可以影响批量导入

以上就是Yii2中JSON数据批量导入MySQL的性能优化实践的详细内容,更多请关注php中文网其它相关文章!


# 多条  # 禹州seo优化排名  # 网站建设售前说明书  # 什么叫seo啊  # 泰国美食推广营销  # 石家庄整合营销推广中心  # 郑州网站推广河南  # 宁波seo自然优化技术  # 朝阳哪家建设网站好  # 惠山区企业网站推广平台  # 网站建设公  # 特殊字符  # 行数  # 数万  # 淘宝  # 网上  # mysql  # 数据库查询  # 上传  # 购物系统  # 加载  # 优化实践  # 性能瓶颈  # sql语句  # 应用开发  # yii  # app  # go  # json  # js  # php 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: 京东单号查询入口_京东快递订单追踪入口  如何将一个大型PHP应用拆分为多个Composer包_微服务与模块化架构的Composer实践  解决 Vaadin 8 中大文件音频播放与定位时出现的 IOException  Win11怎么隐藏桌面图标 Win11一键隐藏所有桌面元素及恢复显示  Google翻译怎么语音输入_Google翻译语音输入功能使用与设置方法  Win11蓝牙耳机断连怎么解决 Win11蓝牙设置重新配对与驱动更新【技巧】  QQ邮箱网页版登录入口 QQ邮箱官方在线使用平台  机器学习中对数变换预测结果的反向还原  Lar*el 递归关系中排除指定分支的教程  J*a最大堆Heapify方法修复:索引计算与边界条件深度解析  漫蛙漫画网页端入口 漫蛙2官方正版漫画站点  Android Studio计算器C键功能异常排查与修复教程  PySpark中高效提取字符串右侧可变长度数字:使用regexp_extract  手机屏幕碎了但能正常使用怎么办 手机外屏碎裂的修复建议  谷歌浏览器如何快速清除某个网站的数据_Chrome网站缓存清理方法  Django AJAX 文件上传教程:解决图片无法保存到模型的常见问题  Win11如何使用Windows Sandbox Win11沙盒功能开启与使用教程【详解】  J*aScript实现单选按钮与关联输入框的联动禁用教程  PS5 Pro有点优势但不多! 《燕云十六声》PS5平台与PC性能画面对比  优化 Python 函数中的条件逻辑:解决 if-else 嵌套与参数选择问题  2026春节假期时间安排 2026春节假日查询  如何在J*a中使用Locale处理多语言环境  c++中为什么推荐使用using替代typedef_c++现代化类型别名  字由网在线版登录地址 字由网网页版安全入口  Python大型XML文件高效流式解析教程  绝地鸭卫平a核爆刀流玩法攻略  千牛数据看板网页版_千牛数据看板网页版访问方法  NetBeans Ant项目:自动化将资源文件复制到dist目录的教程  快手赚钱渠道_快手收益来源  MAC的“快捷指令”怎么同步到iPhone_MAC利用iCloud同步所有设备的自动化指令  微博网页版主页入口 微博官方网站免登录访问  抖音创作助手登录入口_抖音创作辅助工具官网直达  Bing引擎入口最新2025 Bing搜索免费官方登录  在Runstone环境中高效处理TasteDive API的JSON数据  Lar*el Excel导入时生成自定义递增ID的策略与实践  解决移动端滚动问题的overflow属性应用指南  优化MinIO list_objects_v2 操作的性能瓶颈与最佳实践  html两个JS只运行一个怎么办_让双JS在html中都运行方法【技巧】  微信网页版扫码登录入口 微信网页版二维码登录入口  58动漫网在线官方网 58动漫网正版动漫入口网址  Word2013如何插入视频和音频媒体_Word2013媒体插入的多媒体支持  如何修改开机登录密码_Windows账户安全设置超详细教程【必学】  HTML5原生日期选择器与jQuery UI:实现日期选择器的联动与程序化控制  J*a里如何使用N*igableMap进行导航操作_可导航Map操作技巧解析  迅雷下载到U盘速度很慢怎么办_迅雷U盘下载慢优化方法  word中如何让数字纵向排列_Word数字纵向排列方法  高德地图家和公司地址在哪设置 高德地图通勤路线设置方法【超详细】  QQ邮箱登录首页官网地址2026 QQ邮箱官方网页入口  小米14应用无法联网原因分析_小米14网络权限修复  React列表渲染与独立状态管理:避免全局状态影响局部更新 

搜索