问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

MySQL高效批量插入:提升Insert语句性能的实用技巧

创作时间:
作者:
@小白创作中心

MySQL高效批量插入:提升Insert语句性能的实用技巧

引用
CSDN
9
来源
1.
https://blog.csdn.net/weixin_44186319/article/details/140268806
2.
https://m.blog.csdn.net/qq_48811377/article/details/141725548
3.
https://blog.csdn.net/2401_86087607/article/details/140074903
4.
https://blog.csdn.net/rgrgrwfe/article/details/144299978
5.
https://m.blog.csdn.net/zyshen123/article/details/79667977
6.
https://blog.csdn.net/breaksoftware/article/details/139537374
7.
https://docs.pingcode.com/baike/2086737
8.
https://www.cnblogs.com/harda/articles/16993718.html
9.
https://www.cnblogs.com/BlueBlueSea/p/16905334.html

在数据库应用开发中,批量插入数据是一个常见的需求场景。无论是数据迁移、初始数据填充,还是定期的数据同步,高效的批量插入都能显著提升操作效率。本文将深入探讨MySQL中批量插入的最佳实践和性能优化策略,帮助开发者掌握这项关键技能。

01

批量插入的优势与基本原理

批量插入相比单条插入具有显著的性能优势。每次与数据库建立连接都需要初始化和权限验证等步骤,批量插入可以降低这部分开销。更新多条记录的耗时几乎与单条记录相当,批量处理能显著提高吞吐量。

02

最佳实践

合理设置批大小

批大小并非越大越好,需要根据具体场景测试找到最优值。例如,在某些情况下,50-100条记录为一批较为合适。如果数据量过大,可以采用分批处理的方式。比如将5000条数据按照1000条一批进行插入:

List<Student> list = new ArrayList<>();
//向集合中放入5000条数据, 根据实际情况来
// ...

int batchSize = 1000;
int size = list.size();
for (int i = 0; i < size; i += batchSize) {
    int end = Math.min(i + batchSize, size);
    List<Student> subList = list.subList(i, end);
    super.saveBatch(subList);
}

使用事务管理

关闭自动提交并手动管理事务可以进一步提升性能。在Java中可以通过以下方式实现:

try (Connection conn = DriverManager.getConnection(url, user, password)) {
    conn.setAutoCommit(false); // 关闭自动提交
    String sql = "INSERT INTO your_table (column_name) VALUES (?)";
    PreparedStatement pstmt = conn.prepareStatement(sql);

    for (int i = 0; i < dataList.size(); i++) {
        pstmt.setString(1, dataList.get(i));
        pstmt.addBatch();

        if ((i + 1) % batchSize == 0 || (i + 1) == dataList.size()) {
            pstmt.executeBatch();
            conn.commit(); // 提交事务
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}
03

性能优化策略

优化SQL语句

使用INSERT INTO table VALUES (...),(...),...格式进行批量插入。对于MyISAM引擎,可通过禁用索引(ALTER TABLE tb_name DISABLE KEYS;)和唯一性检查(SET UNIQUE_CHECKS=0;)来加速插入。对于InnoDB引擎,除了上述方法外,还可通过调整配置参数(如innodb_buffer_pool_sizebulk_insert_buffer_size等)优化性能。

数据有序插入

数据有序的插入是指插入记录在主键上是有序排列。由于数据库插入时需要维护索引数据,无序的记录会增大维护索引的成本。我们可以参照InnoDB使用的B+tree索引,如果每次插入记录都在索引的最后面,索引的定位效率很高,并且对索引调整较小;如果插入的记录在索引中间,需要B+tree进行分裂合并等处理,会消耗比较多计算资源,并且插入记录的索引定位效率会下降,数据量较大时会有频繁的磁盘操作。

综合优化策略

使用合并数据+事务+有序数据的方式在数据量达到千万级以上表现依旧是良好,在数据量较大时,有序数据索引定位较为方便,不需要频繁对磁盘进行读写操作,所以可以维持较高的性能。

04

实际案例

在实际项目中,我们经常会遇到需要生成大量测试数据的情况。以下是使用MySQL存储过程和函数生成随机数据的示例:

-- 随机产生字符串
DELIMITER $$
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str = CONCAT(return_str, SUBSTRING(chars_str, FLOOR(1 + RAND() * 52), 1));
SET i = i + 1;
END WHILE;
RETURN return_str;
END $$
-- 插入角色数据
DELIMITER $$
CREATE PROCEDURE insert_role(max_num INT)
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO role (role_name, orders) VALUES (rand_string(8), rand_num(1, 5000));
UNTIL i = max_num
END REPEAT;
COMMIT;
END$$

执行存储过程插入10万条数据:

CALL insert_role(100000);

测试结果显示,使用上述优化方法后,插入10万条数据仅需约半分钟,而100万条数据则需要20分钟以上。在实际应用中,建议结合具体场景进行性能测试,以找到最优的批处理大小和优化策略。

通过本文的介绍,相信读者已经掌握了MySQL批量插入的核心技巧和优化策略。在实际项目中,合理运用这些方法,可以显著提升数据插入效率,优化系统性能。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号