4分钟插入1000万条数据到mysql数据库表

本文介绍如何使用Java JDBC批量向MySQL数据库插入1000万条数据,通过调整数据库配置和优化SQL语句,实现高效的数据插入,并对比不同数据库引擎的性能差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.cnblogs.com/fanwencong/p/5765136.html

我用到的数据库为,mysql数据库5.7版本的

1.首先自己准备好数据库表

其实我在插入1000万条数据的时候遇到了一些问题,现在先来解决他们,一开始我插入100万条数据时候报错,控制台的信息如下:

com.mysql.jdbc.PacketTooBigException: Packet for query is too large (4232009 > 4194304). You can change this value on the server by setting the max_allowed_packet’ variable.

出现上面的错误是因为数据库表的 max_allowed_packet这个配置没配置足够大,因为默认的为4M的,后来我调为100M就没报错了

set global max_allowed_packet = 100*1024*1024*
记住,设置好后重新登录数据库才能看的设置后的值show VARIABLES like '%max_allowed_packet%'
Java的jdbc代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package insert;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
 
import com.mysql.jdbc.PreparedStatement;
 
public class InsertTest {
 
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        final String url = "jdbc:mysql://127.0.0.1/teacher"
        final String name = "com.mysql.jdbc.Driver"
        final String user = "root"
        final String password = "123456"
        Connection conn = null
        Class.forName(name);//指定连接类型 
        conn = DriverManager.getConnection(url, user, password);//获取连接 
        if (conn!=null) {
            System.out.println("获取连接成功");
            insert(conn);
        }else {
            System.out.println("获取连接失败");
        }
 
    }
    public static void insert(Connection conn) {
        // 开始时间
        Long begin = new Date().getTime();
        // sql前缀
        String prefix = "INSERT INTO t_teacher (id,t_name,t_password,sex,description,pic_url,school_name,regist_date,remark) VALUES ";
        try {
            // 保存sql后缀
            StringBuffer suffix = new StringBuffer();
            // 设置事务为非自动提交
            conn.setAutoCommit(false);
            // 比起st,pst会更好些
            PreparedStatement  pst = (PreparedStatement) conn.prepareStatement("");//准备执行语句
            // 外层循环,总提交事务次数
            for (int i = 1; i <= 100; i++) {
                suffix = new StringBuffer();
                // 第j次提交步长
                for (int j = 1; j <= 100000; j++) {
                    // 构建SQL后缀
                    suffix.append("('" + uutil.UUIDUtil.getUUID()+"','"+i*j+"','123456'"",'男'"+",'教师'"+",'www.bbk.com'"+",'XX大学'"+",'"+"2016-08-12 14:43:26"+"','备注'" +"),");
                }
                // 构建完整SQL
                String sql = prefix + suffix.substring(0, suffix.length() - 1);
                // 添加执行SQL
                pst.addBatch(sql);
                // 执行操作
                pst.executeBatch();
                // 提交事务
                conn.commit();
                // 清空上一次添加的数据
                suffix = new StringBuffer();
            }
            // 头等连接
            pst.close();
            conn.close();
        catch (SQLException e) {
            e.printStackTrace();
        }
        // 结束时间
        Long end = new Date().getTime();
        // 耗时
        System.out.println("1000万条数据插入花费时间 : " + (end - begin) / 1000 " s");
        System.out.println("插入完成");
    }
}

  结果:

哈哈,1000万条数据288秒完成,是不是感觉超级牛逼,我每次插入10万条数据就提交一次事务,如果是一条一条差的话估计要好几个小时,网上有人试过时间浪费在数据库的连接上了,
后来我想测试插入100万条数据时候数据库引擎的差别
首先把代码中最外层的循环i=100改为i=10;
1.数据库引擎为MyISAM时:27s,这个我忘了截图了。因为我后来测试InnoDB的时候我换了一个表来测试,因为我发现改不了数据库表的引擎。。。。所以只能换一个表来测试
1.数据库引擎为InnoDB时:

 用了77秒,比MyISAW慢了3倍左右,估计要是1000万条数据的时候更慢吧。。。
<think>嗯,用户问怎么优化往数据库插入1000万条数据的操作。这个问题挺常见的,但处理大数据插入确实需要仔细考虑。首先,我得回忆一下常见的优化手段,然后逐步分析每个可能的优化点。 首先,用户可能是在做数据迁移或者初始化大量数据,比如测试环境的数据填充。这时候,单条插入肯定不行,因为每次插入都有网络开销和事务日志的开销。所以,第一个想到的是批量插入。比如,用INSERT INTO ... VALUES (),(),()的方式,一次性插入多条记录。这样可以减少数据库的交互次数,提升效率。不过,批量的大小需要合适,不能太大,否则可能会超出数据库的限制或者内存问题。通常,每批1000条左右比较合适,但具体还得看数据库和配置。 然后,事务的处理。如果每条插入都自动提交,那会有很大的性能损耗。所以,应该把多个批量操作放在一个事务里提交,减少事务提交的次数。不过,事务太大也可能导致日志文件增长过快,或者锁的问题,需要平衡。 接下来,预处理语句,比如使用PreparedStatement,这样可以避免SQL解析的开销,数据库可以缓存执行计划,提高效率。特别是在循环中重复执行相似的SQL时,预处理能明显提升速度。 还有,调整数据库的配置参数。比如,增大innodb_buffer_pool_size(如果是MySQL的话),让更多的数据在内存中处理,减少磁盘IO。另外,关闭自动提交,设置unique_checks和foreign_key_checks为0,插入完成后再恢复,这些都能减少检查的开销。不过需要注意,关闭外键检查可能会有数据不一致的风险,所以得确保数据本身没有问题。 然后,考虑禁用索引。在插入大量数据时,索引的维护会占用很多时间。可以先删除索引,插入数据后再重建索引。特别是聚集索引,如果主键是自增的,按顺序插入可以减少页分裂,提升速度。 数据加载工具也是一个点。像MySQL的LOAD DATA INFILE,或者PostgreSQL的COPY命令,这些工具比普通的INSERT快很多,因为它们是专门为批量数据导入设计的,直接读写文件,效率更高。 并行插入的话,如果数据库支持,可以多线程或者分批次处理,但要注意避免锁竞争。比如,按主键范围分成多个任务,同时插入不同的分区,不过需要系统资源足够,比如CPU、磁盘IO不能成为瓶颈。 另外,设计方面,如果字段很多,可以考虑拆分,先插入必要的字段,后续再更新其他字段。或者使用更紧凑的数据类型,减少存储空间,提高处理速度。 硬件方面,如果可能的话,提升磁盘性能,比如使用SSD,增加内存,或者优化数据库服务器的配置,比如调整日志文件的存放位置,使用更快的存储设备。 还有,在插入前进行数据预处理,比如去重、格式化,避免在插入过程中因为数据错误导致回滚或者中断。预处理好的数据能更顺畅地插入。 最后,测试和监控很重要。先用小批量数据测试方案的有效性,观察数据库的负载情况,比如CPU、内存、IO的使用率,根据实际情况调整参数。比如,如果发现磁盘IO很高,可能需要调整缓冲区大小或者优化磁盘配置。 不过,用户可能有特定的场景,比如使用的数据库类型不同(MySQL、PostgreSQL等),或者数据是否已经预处理好,是否有网络传输的延迟(比如远程数据库)。这些因素都会影响优化的策略。需要根据具体情况选择合适的优化方法,有时候需要结合多种策略才能达到最佳效果。</think>以下是分步骤优化千万级数据插入的完整方案: 一、基础优化阶段(3-5倍提升) 1. 批量插入优化 - 使用批量插入语句:$$INSERT INTO table (col1,col2) VALUES (v1,v2),(v3,v4)...$$ - 推荐每批500-1000条(需测试确定最佳值) - 示例代码(Java): ```java String sql = "INSERT INTO table (a,b) VALUES (?,?)"; PreparedStatement ps = conn.prepareStatement(sql); for (int i=0; i<1e7; i++) { ps.setInt(1, value1); ps.setInt(2, value2); ps.addBatch(); if(i%1000 == 0) { ps.executeBatch(); conn.commit(); } } ``` 2. 事务优化 - 合并多个批量操作为一个事务 - 设置`autocommit=0`后手动提交 二、中级优化(5-10倍提升) 3. 参数调优 ```sql SET unique_checks = 0; -- 禁用唯一约束检查 SET foreign_key_checks = 0; -- 禁用外键检查 SET sql_log_bin = 0; -- 非主从环境禁用二进制日志 ``` 4. 索引优化 ```sql ALTER TABLE table_name DROP INDEX index_name; -- 插入前删除非主键索引 -- 插入数据... ALTER TABLE table_name ADD INDEX index_name(column); -- 完成后重建 ``` 三、高级优化(10倍+提升) 5. 使用专用加载工具 - MySQL示例: ```sql LOAD DATA INFILE '/path/file.csv' INTO TABLE table FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'; ``` 6. 结构优化 - 使用`TABLESPACE`分离数据与索引存储 - 调整`ROW_FORMAT=COMPRESSED` 四、分布式方案(适用于超大规模) 7. 分库分插入 - 按哈希值分10个线程并行插入 - 每个线程处理100万条数据 - 使用连接池管理数据库连接 五、配套优化措施 8. 服务器参数调整 ```ini # MySQL my.cnf 配置 innodb_flush_log_at_trx_commit = 0 innodb_buffer_pool_size = 80%内存 bulk_insert_buffer_size = 256M ``` 9. 硬件优化 - 使用SSD固态硬盘 - 确保服务器内存≥32GB - 配置RAID 10磁盘阵列 六、实施注意事项 1. 始终保留数据库备份 2. 在测试环境验证方案 3. 监控服务器资源(CPU/内存/IO) 4. 分阶段提交(每50万条做一次checkpoint) 5. 完成后执行`ANALYZE TABLE`更新统计信息 典型性能对比: - 原始逐条插入:约 1000条/秒 - 优化后方案:可达 50000条/秒 - 总耗时从2.7小时降至约5分钟 建议先使用`EXPLAIN`分析执行计划,通过小批量测试(如1万条)验证优化效果后再进行全量操作。不同数据库(Oracle/PostgreSQL/SQL Server)需调整具体参数,但核心原理相通。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值