Mysql 数据库插入 1w 条数据用了多久?

最近做个批量获取客户公众号粉丝的功能,但是客户粉丝量过万的时候,需要做批量插入处理,但微信每次返回1万。

微信接口文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/Getting_a_User_List.html

 public function actionGetOpenidList()
    {
        set_time_limit(0);
        date_default_timezone_set("PRC");
        $storeList = Store::find()->where(['is_delete' => 0,'is_recycle' => 0])->select(['id', 'wechat_app_id'])->asArray()->all();
        if (empty($storeList)) {
            return;
        }
        //遍历商户
        foreach ($storeList as $k => $v) {
            try {
                $this->store = $v;
                echo ('--start--' . $this->store['id']) . PHP_EOL;
                $form = new MemberFrom();
                $wx = $form->getWx($this->store['id']);
                if(!$wx){
                    \Yii::error("获取公众号用户openid消息出错:'商户ID'.$this->store['id'].'实例化公众号失败'\n");
                    continue;
                }
                $token = $wx->getAccessToken(1); //强制使用公众号token
                if(!$token){
                    \Yii::error("获取公众号用户openid消息出错:'商户ID'.$this->store['id'].'公众号token获取失败'\n");
                    continue;
                }
                $fansArr = $form->getOpenidList($token);
                $nextOpenid = $fansArr['next_openid'];
                $attributes = [];
                foreach ($fansArr['data']['openid'] as $item) {
                    $flag = StoreOpenidUnion::find()->where(['wechat_platform_open_id' => $item, 'store_id' => $this->store['id']])->one();
                    if ($flag) {
                        continue;
                    } else {
                        $attributes[] = [
                            $this->store['id'], $item, '', time()
                        ];
                    }
                }
                if($attributes){
                    $insert = \Yii::$app->db->createCommand()->batchInsert(StoreOpenidUnion::tableName(), ['store_id', 'wechat_platform_open_id', 'wechat_union_id', 'add_time'], $attributes)->execute();
                    usleep(1000000);
                    if (!$insert) {
                        \Yii::error("批量插入失败:'商户ID'.$this->store['id'].'\n");
                    }
                    unset($attributes);
                }

                if($fansArr['total']>10000){
                    //for ($i=0;$i<=floor($fansArr['total']/$fansArr['count'])-1;$i++){
                    for ($i=0;$i<=floor($fansArr['total']/10000)-1;$i++){
                        if ($nextOpenid) {
                            $fansArrMore = $form->getOpenidList($token,$nextOpenid);
                            $nextOpenid = $fansArrMore['next_openid'];
                            $attributes1 = [];
                            foreach ($fansArrMore['data']['openid'] as $item) {
                                $flag = StoreOpenidUnion::find()->where(['wechat_platform_open_id' => $item, 'store_id' => $this->store['id']])->one();
                                if ($flag) {
                                    continue;
                                } else {
                                    $attributes1[] = [
                                        $this->store['id'], $item, '', time()
                                    ];
                                }
                            }
                            if($attributes1){
                                $insert1 = \Yii::$app->db->createCommand()->batchInsert(StoreOpenidUnion::tableName(), ['store_id', 'wechat_platform_open_id', 'wechat_union_id', 'add_time'], $attributes1)->execute();
                                usleep(1000000);
                                if (!$insert1) {
                                    \Yii::error("批量插入失败:'商户ID'.$this->store['id'].'\n");
                                }
                                unset($attributes1);
                            }
                        }
                    }
                }
            }catch (\Exception $e) {
                $e->getMessage();
            }
        }
    }

疑问,mysql插入过万数据需要多长?插入的形式有哪些?mysql是怎么执行?

  1. 多线程插入(单表)
  2. 多线程插入(多表)
  3. 预处理sql 
  4. 多值插入sql
  5. 事务( N 条提交一次)

多线程插入单表:为何对同一个表的插入多线程会比单线程快?同一时间对一个表的写操作不应该是独占的吗?

answer:在数据里做插入操作的时候,整体时间的分配是这样的

  • 链接耗时 (30%)

  • 发送 query 到服务器 (20%)

  • 解析 query (20%)

  • 插入操作 (10% * 词条数目)

  • 插入 index (10% * Index的数目)

  • 关闭链接 (10%)

因此真正耗时间的是连接和解析,不是操作!

MySQL 插入数据在写阶段是独占的,但是插入一条数据仍然需要解析、计算、最后才进行写处理,比如要给每一条记录分配自增 id,校验主键唯一键属性,或者其他一些逻辑处理,都是需要计算的,所以说多线程能够提高效率。

预处理方式:

  1. 普通 SQL,即使用 Statement 接口执行 SQL
  2. 预处理 SQL,即使用 PreparedStatement 接口执行 SQL

使用 PreparedStatement 接口允许数据库预编译 SQL 语句,以后只需传入参数,避免了数据库每次都编译 SQL 语句,因此性能更好。

多值插入:

  • 普通插入 SQL:INSERT INTO TBL_TEST (id) VALUES(1)

  • 多值插入 SQL:INSERT INTO TBL_TEST (id) VALUES (1), (2), (3)

使用多值插入 SQL,SQL 语句的总长度减少,即减少了网络 IO,同时也降低了连接次数,数据库一次 SQL 解析,能够插入多条数据。

 

事务( N 条提交一次)

在一个事务中提交大量 INSERT 语句可以提高性能。将 sql 拼接成字符串,每 1000 条左右提交事务。10w 条数据大概用时 10s!也就是1次0.1秒!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值