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秒!

A:请提供更多上下文信息,例如具体的数据库类型、数据结构、需要插入数据字段以及数据来源等。稍加思考,大致步骤如下: 1. 准备好待插入1w动态数据。 2. 连接数据库并打开一个事务,这样可以保证在出错的情况下能够回滚操作。 3. 循环插入每一数据,可以选择使用批量插入来优化性能,具体实现方式取决于数据库类型和数据访问框架。在插入数据的同时,注意处理异常情况。 4. 插入完毕后提交事务并关闭数据库连接。 以下是一个MySQL数据库的示例代码(仅供参考,具体实现方式视情况而定): ``` import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class InsertDataExample { private static final int NUM_ROWS = 10000; private static final String DB_URL = "jdbc:mysql://localhost:3306/mydatabase"; private static final String DB_USER = "myuser"; private static final String DB_PASSWORD = "mypassword"; public static void main(String[] args) { try { // Connect to the database and open a new transaction Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); conn.setAutoCommit(false); // Prepare the INSERT statement PreparedStatement stmt = conn.prepareStatement( "INSERT INTO mytable (field1, field2, field3) VALUES (?, ?, ?)"); // Insert the data using batch processing for (int i = 0; i < NUM_ROWS; i++) { // Generate the dynamic data for each row String field1 = "value" + i; int field2 = i; String field3 = "another value" + i; // Bind the values to the INSERT statement stmt.setString(1, field1); stmt.setInt(2, field2); stmt.setString(3, field3); // Add the statement to the batch stmt.addBatch(); } // Execute the batch and commit the transaction stmt.executeBatch(); conn.commit(); // Clean up resources stmt.close(); conn.close(); } catch (SQLException e) { // Handle any errors by rolling back the transaction and rethrowing try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值