ITPub博客

首页 > > > 你向 Mysql 数据库插入 100w 条数据用了多久?

你向 Mysql 数据库插入 100w 条数据用了多久?

作者:孤独键客 时间:2020-05-14 13:46:14 0 删除 编辑
程序员的成长之路
互联网/程序员/成长/职场 
关注


阅读本文大概需要 2 分钟。


▌目录


多线程插入(单表)
多线程插入(多表)
预处理 SQL
多值插入 SQL
事务( N 条提交一次)


▌多线程插入(单表)


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


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


  • 链接耗时 (30%)

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

  • 解析 query (20%)

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

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

  • 关闭链接 (10%)


从这里可以看出来,真正耗时的不是操作,而是链接,解析的过程。


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


▌多线程插入(多表)


分区分表后使用多线程插入。


▌预处理 SQL


  • 普通 SQL,即使用 Statement 接口执行 SQL

  • 预处理 SQL,即使用 PreparedStatement 接口执行 SQL


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


String sql = "insert into testdb.tuser (name, remark, createtime, updatetime) values (?, ?, ?, ?)"; 
for (int i = ; i < m; i++) { 
    //从池中获取连接 
    Connection conn = myBroker.getConnection(); 
    PreparedStatement pstmt = conn.prepareStatement(sql); 
    for (int k = ; k < n; k++) { 
            pstmt.setString(1, RandomToolkit.generateString(12)); 
            pstmt.setString(2, RandomToolkit.generateString(24)); 
            pstmt.setDate(3, new Date(System.currentTimeMillis())); 
            pstmt.setDate(4, new Date(System.currentTimeMillis())); 
            //加入批处理 
            pstmt.addBatch(); 
    } 
    pstmt.executeBatch();    //执行批处理 
    pstmt.close(); 
    myBroker.freeConnection(conn); //连接归池 
}


▌多值插入 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 语句可以提高性能。


1、将表的存储引擎修改为 myisam


2、将 sql 拼接成字符串,每 1000 条左右提交事务。


/// <summary>  
        /// 执行多条SQL语句,实现数据库事务。  
        /// </summary>mysql数据库  
        /// <param name="SQLStringList">多条SQL语句</param>  
        public void ExecuteSqlTran(List<string> SQLStringList)
        
{
            using (MySqlConnection conn = new MySqlConnection(connectionString))
            {
                if (DBVariable.flag)
                {
                    conn.Open();
                    MySqlCommand cmd = new MySqlCommand();
                    cmd.Connection = conn;
                    MySqlTransaction tx = conn.BeginTransaction();
                    cmd.Transaction = tx;
                    try
                    {
                        for (int n = ; n < SQLStringList.Count; n++)
                        {
                            string strsql = SQLStringList[n].ToString();
                            if (strsql.Trim().Length > 1)
                            {
                                cmd.CommandText = strsql;
                                cmd.ExecuteNonQuery();
                            }
                            //后来加上的  
                            if (n >  && (n % 1000 ==  || n == SQLStringList.Count - 1))
                            {
                                tx.Commit();
                                tx = conn.BeginTransaction();
                            }
                        }
                        //tx.Commit();//原来一次性提交  
                    }
                    catch (System.Data.SqlClient.SqlException E)
                    {
                        tx.Rollback();
                        throw new Exception(E.Message);
                    }
                }
            }
        }


10w 条数据大概用时 10s!




往期精彩回顾

19 条效率至少提高 3 倍的 MySQL 技巧

从零开始 Code Review,两年实战经验分享!

一次心惊肉跳的服务器误删文件的恢复过程

JVM 最多支持多少个线程?

一条简单的 SQL 执行超过 1000ms,纳尼?

这群开发者,每月至少能从 App store 躺骗几十万

如何优雅地给妹子优化电脑?(技巧篇)

写留言

喜欢就给个“在看”

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69902700/viewspace-3165028/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
一个不羁的码农,终身学习者。公众号「程序员的成长之路」。目前就职于一家游戏公司,主要负责服务器端,以及web系统的开发工作,对Java相关知识比较擅长。

注册时间:2018-12-14

  • 博文量
    793
  • 访问量
    119851