数据库批量数据插入问题分析

数据库领域:SQL 批量插入数据的高效方式 在数据库应用中,数据的插入操作是非常常见的。当需要插入大量数据时,传统的单条插入方式会因为频繁的数据库交互而导致性能低下。本文章的目的就是探讨如何采用高效的方式进行 SQL 批量插入数据,以提高数据库的处理效率。我们将涵盖多种数据库系统(如 MySQL、PostgreSQL、SQL Server 等)中常用的批量插入方法,并分析它们的优缺点和适用场景。本文将按照以下结构进行阐述:首先介绍 SQL 批量插入的核心概念与联系,包括其原理和架构; 阅读详情
 
在数据库的相关开发中,经常会遇到数据的批量插入问题。本文主要是通过实验的方式探讨批量数据插入的瓶颈,以及优化建议。


以10w条记录的插入作为实验对象,采用下面的几种方法插入:

1.       普通插入:普通的一条条插入

2.       普通插入+手动提交:setAutoCommit(false)、commit()

3.       普通插入+手动提交+ prepareStatement方式

4.       批量插入:addBatch、executeBatch

5.       批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,

6.       多线程插入。

7.       InnoDB引擎和MyISAM引擎的比较。


实验环境:

数据库:MySQL 5.0

机器硬件:

内存 3G 

CPU AMD双核4400+ 2.3G

首先建立一个简单的user表:

CREATE TABLE `user` (                                         

          `id` varchar(50) NOT NULL,                                  

          `seqid` bigint(20) NOT NULL auto_increment,                 

          `name` varchar(50) NOT NULL,                                 

          PRIMARY KEY (`seqid`)

        ) ENGINE=MyISAM DEFAULT CHARSET=utf8

一、普通插入
代码:

 1Connection conn=source.getConnection();
 2Statement s=conn.createStatement();
 3String sql="";
 4long start=System.currentTimeMillis();
 5for(int i=0;i<100000;i++)
 6{
 7    sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";
 8    s.execute(sql);
 9}
10s.close();
11conn.close();
12long end=System.currentTimeMillis();
13System.out.println("commonInsert()执行时间为:"+(end-start)+"ms");
输出结果:
commonInsert()执行时间为:13828ms

二、普通插入+手动提交:setAutoCommit(false)、commit()
代码:
 1Connection conn=source.getConnection();
 2conn.setAutoCommit(false);
 3Statement s=conn.createStatement();
 4String sql="";
 5long start=System.currentTimeMillis();
 6for(int i=0;i<100000;i++)
 7{
 8   sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";
 9   s.execute(sql);
10}
11conn.commit();
12s.close();
13conn.close();
14long end=System.currentTimeMillis();
15System.out.println("commonInsert()执行时间为:"+(end-start)+"ms");
输出结果:
commonInsert()执行时间为:13813ms
对比分析:
可以看出,仅仅是这种方式的设置,对性能的影响并不大。

三、普通插入+手动提交+ prepareStatement方式
代码:
 1Connection conn=source.getConnection();
 2        conn.setAutoCommit(false);
 3        PreparedStatement ps=conn.prepareStatement("insert into user(id,name) value(?,?)");
 4        long start=System.currentTimeMillis();
 5        for(int i=0;i<100000;i++)
 6        {
 7            ps.setString(1,(i+1)+"");
 8            ps.setString(2,"chenxinhan");
 9            ps.execute();
10        }
11        conn.commit();
12        ps.close();
13        conn.close();
14        long end=System.currentTimeMillis();
15        System.out.println("prepareStatementInsert()执行时间为:"+(end-start)+"ms");
输出结果:
prepareStatementInsert()执行时间为:12797ms
对比分析:
采用prepareStatement的方式确实可以提高一点性能,因为减少了数据库引擎解析优化SQL语句的时间,但是由于现在的插入语句太简单,所以性能提升不明显。

四、批量插入:addBatch、executeBatch
代码:
 1        Connection conn=source.getConnection();
 2        conn.setAutoCommit(false);
 3        Statement s=conn.createStatement();
 4        String sql="";
 5        long start=System.currentTimeMillis();
 6        for(int j=0;j<100;j++)
 7        {
 8            for(int i=0;i<1000;i++)
 9            {
10                sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";
11                s.addBatch(sql);
12            }
13            s.executeBatch();
14            conn.commit();
15            s.clearBatch();
16        }
17        s.close();
18        conn.close();
19        long end=System.currentTimeMillis();
20        System.out.println("batchInsert()执行时间为:"+(end-start)+"ms");
输出结果:
batchInsert()执行时间为:13625ms
对比分析:
按道理,这种批处理的方式是要快些的,但是测试结果却不尽人意,有点不解,请高人拍砖。

五、批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,
代码:
 1Connection conn=source.getConnection();
 2        conn.setAutoCommit(false);
 3        Statement s=conn.createStatement();
 4        StringBuilder sql=new StringBuilder("");
 5        long start=System.currentTimeMillis();
 6        for(int j=0;j<100;j++)
 7        {
 8            sql=new StringBuilder("");
 9            sql.append("insert into user(id,name) values ");
10            for(int i=0;i<1000;i++)
11            {
12                if(i==999)
13                    sql.append("('").append(i+1).append("',").append("'cxh')");
14                else
15                    sql.append("('").append(i+1).append("',").append("'cxh'),");
16            }
17            s.execute(sql.toString());
18            conn.commit();
19        }
20        s.close();
21        conn.close();
22        long end=System.currentTimeMillis();
23        System.out.println("manyInsert()执行时间为:"+(end-start)+"ms");
输出结果:
manyInsert()执行时间为:937ms
对比分析:
发现采用这种方式的批量插入性能提升最明显,有10倍以上的性能提升。所以这种方式是我推荐的批量插入方式!

六、多线程插入
在第五种方式的基础上采用多线程插入。
代码:
 1final Connection conn=source.getConnection();
 2        for(int j=0;j<3;j++)
 3        {
 4            Thread t=new Thread(){
 5                @Override
 6                public void run() {
 7                    try
 8                    {
 9                        long start=System.currentTimeMillis();
10                        Statement s=conn.createStatement();
11                        StringBuilder sql=new StringBuilder("");
12                        for(int j=0;j<100;j++)
13                        {
14                            conn.setAutoCommit(false);
15                            sql=new StringBuilder("");
16                            sql.append("insert into user (id,name) values ");
17                            for(int i=0;i<1000;i++)
18                            {
19                                if(i==999)
20                                    sql.append("('").append(i+1).append("',").append("'cxh')");
21                                else
22                                    sql.append("('").append(i+1).append("',").append("'cxh'),");
23                            }
24                            s.execute(sql.toString());
25                            conn.commit();
26                        }
27                        s.close();
28                        long end=System.currentTimeMillis();
29                        System.out.println("multiThreadBatchInsert()执行时间为:"+(end-start)+"ms");
30                    }
31                    catch(Exception e)
32                    {
33                        e.printStackTrace();
34                    }
35                }
36            };
37            t.start();
38            //t.join();
39        }
输出结果:
multiThreadBatchInsert()执行时间为:2437ms
multiThreadBatchInsert()执行时间为:2625ms
multiThreadBatchInsert()执行时间为:2703ms

注意:上面我采用的是三个线程插入30w条数据。
取最大时间为2703ms,较上面的937ms,基本还是三倍的时间。
所以发现此时多线程也解决不了批量数据插入问题。原因就是,这时候的性能瓶颈不是CPU,而是数据库!

七、InnoDB引擎和MyISAM引擎的比较
最后,分析一下,这两个引擎对批量数据插入的影响。
先建立user2数据表:

CREATE TABLE `user2` (                                         

          `id` varchar(50) NOT NULL,                                  

          `seqid` bigint(20) NOT NULL auto_increment,                 

          `name` varchar(50) NOT NULL,                                 

          PRIMARY KEY (`seqid`)

        ) ENGINE=InnoDB DEFAULT CHARSET=utf8

代码:
 1Connection conn=source.getConnection();
 2        conn.setAutoCommit(false);
 3        Statement s=conn.createStatement();
 4        StringBuilder sql=new StringBuilder("");
 5        long start=System.currentTimeMillis();
 6        for(int j=0;j<100;j++)
 7        {
 8            sql=new StringBuilder("");
 9            sql.append("insert into user2 (id,name) values ");
10            for(int i=0;i<1000;i++)
11            {
12                if(i==999)
13                    sql.append("('").append(i+1).append("',").append("'cxh')");
14                else
15                    sql.append("('").append(i+1).append("',").append("'cxh'),");
16            }
17            s.execute(sql.toString());
18            conn.commit();
19        }
20        s.close();
21        conn.close();
22        long end=System.currentTimeMillis();
23        System.out.println("manyInsert2()执行时间为:"+(end-start)+"ms");
输出结果:
manyInsert2()执行时间为:3484ms
注意:第七项的代码和第五是一样的,除了数据表名称不同(user、user2)
但是,
InnoDB :3484ms
MyISAM:937ms
所以,MyISAM引擎对大数据量的插入性能较好。

总结:
对于大数据量的插入,建议使用insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,的方式,引擎建议使用MyISAM引擎。
FFmpeg硬件加速实战:VAAPI驱动配置全攻略(含NVIDIA/Intel避坑指南) 本文详细解析了在Linux环境下配置FFmpeg使用VAAPI接口实现硬件加速的完整流程。针对NVIDIA、Intel等主流显卡,提供了从驱动安装、环境变量设置到多显卡切换的实战指南,并重点解决了闭源驱动冲突、国产系统适配等常见问题,帮助用户有效提升视频处理性能。 阅读详情

相关推荐

Windows 11 IoT企业版LTSC 24H2/25H2中文版安装指南(含OEM激活教程)

本文详细介绍了Windows 11 IoT企业版LTSC 24H2/25H2中文版的安装与OEM激活全流程。从系统镜像准备、硬件兼容性检查到自动化安装配置,再到OEM激活方案(包括SLIC注入和数字许可证激活),为工业自动化、数字标牌等物联网设备提供稳定可靠的系统部署指南。

weixin_29198045的博客 8921

多线程批量插入数据

1.多线程实现方式 继承Thread类, 重写run方法,run里面的代码就是我们开启多线程会执行的业务逻辑 /** * 继承Thread, 重写run方法 */ public class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 2000; i++) { System.out.println(Thread.currentThre

weixin_42450407的博客 6207

ACR 磁共振安全手册 2024 更新版:全面保障 MRI 安全实践

MR 环境:MR 系统周围的三维空间,包含法拉第屏蔽体积和 9 高斯线,医疗设备在此区域可能因暴露于 MR 设备产生的电磁场而构成危险,需进行访问控制以降低风险MR 受控访问区域:MR 系统周围的局部定义区域,包含 MR 环境(包括其静磁场),访问仅限于授权人员MR 抛射物区域:围绕 MRI 系统的 IV 区区域,铁磁物体在此有成为抛射物的风险图一 磁共振环境:场地规划与区域划分。

楚山之石的博客 2604

多线程插入数据开启事务,要么都成功要么都失败,PlatformTransactionManager 管理事务

spring为我们提供了事务相关的接口,PlatformTransactionManager public interface PlatformTransactionManager extends TransactionManager { // 获取当前活动的事务或创建一个新事务 TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws Transactio..

你走过的路 风都是暖的 1465

VSCode关联VIVADO编辑Verilog

有时候接手别人的代码,或者从网上找的开源代码,每个人风格不一致,对齐缩进也不一样,阅读起来很累。有没有什么方法能快捷地格式化代码呢。下面我们利用VSCode插件来实现这个需求。Vivado是Xilinx公司提供的逻辑开发平台(之一),如果不喜欢Vivado自带的文本编辑器,可以选择第三方的文本编辑器VSCode。

小王在努力...的博客 7151

Flutter 完整学习文档 - 从入门到精通

Widget 就像乐高积木,Flutter 中所有的东西都是 Widget。一个按钮是 Widget,一段文字是 Widget,甚至布局、边距、对齐方式也是 Widget!"万物皆 Widget"

zwjapple的专栏 2321

Mysql 批量插入大量数据的两种方案以及优缺点(分别是 5W 条数据和 10W 条数据)

Mysql 批量插入大量数据的两种方案以及优缺点(分别是 5W 条数据和 10W 条数据)

qq_41824825的博客 1万+

FPGA经验谈系列文章——3、逻辑级数

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Xilinx FPGA开发tips系列——前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例可供参考 一、pandas是什么? 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的

gzy0506的博客 1万+

线程与线程池的优缺点比较

线程池通过管理线程的创建、重用和回收来提供更好的性能和资源管理。1、初始化开销:线程池本身的初始化可能需要一些开销,特别是在创建线程池时设置参数的过程中。2、复杂性增加:引入线程池会增加代码的复杂性,需要适当地管理线程池的生命周期和任务提交。1、资源管理:线程池可以管理线程的创建、重用和回收,从而减少了线程创建和销毁的开销。2、提高性能:通过重用线程,可以避免线程创建和销毁的开销,并提高系统的整体性能。3、控制并发度:线程池可以限制并发线程的数量,从而控制资源消耗和避免系统过载。

一个菜鸟从零基础学JAVA的过程 1532

手把手教你学PCIE-- 热插拔电路设计与实现方案

PCIe热插拔(Hot-Plug)技术允许用户在系统运行时安全地插入或移除设备,而无需重启系统。本文将深入讲解热插拔电路的设计要点、关键器件选型及信号协议规范,涵盖机械结构、电气保护和电源管理三大核心模块。​。

MHD0815的博客 440

【2024年华为秋招-12月25日-第三题(300分)- PCB印刷电路板布线】(题目+思路+Java&C++&Python解析+在线测试)

在PCB印刷电路板设计中,器件之间的连线需要避免线路的阻抗值增大、而且赛件之间还有别的器件和别的干扰源,在布线时我们希望受到的干扰尽量小。现将电路板简化成一个M×N的矩阵,每个位置(单元格)的值表示其源干扰度。如果单元格的值为0,表示此位置没有干扰源;如果单元格的值为非0,则表示此位置是干扰源,其值为源干扰度。连线经过干扰源或干扰源附近会增加连线的总干扰度。位置Axy的干扰源的源干扰度为dd01、若连线经过位置Axy,则其总干扰度会增加d;2、若连线经过离位置A。

m0_73659489的博客 344

使用线程池与foreach批量优化一次插入万级以上数据

多线程提高mybati插入效率

qq_45243783的博客 2354

专为AI打造的浏览器:内存占用仅为Chrome的1/9、比Chrome快11倍(Docker部署教程,支持飞牛nas等服务器部署)

🚀 专为AI打造的无头浏览器来了! 用Zig从零构建,内存仅Chrome的1/9,速度快11倍,原生CDP协议支持Docker部署,适合爬虫、自动化测试和AI代理应用。✨

XiaoqiangClub的博客 734

数据库批量插入和存在的问题

mysql批量操作和注意事项

huhu123444的博客 1240

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

达梦数据库中jdbc接口的大批量插入数据的写法推荐

通过查看sqllog日志,发现saveBatch接口使用PreparedStatement预编译多条insert语句 然后executeBatch提交。eg:在DM中没有rewriteBatchedStatements 参数,因为跟mysql的驱动内部的executeBatch()函数实现不同。使用mysql数据库的话通常使用的这种写法。这种写法会导致sql语句会非常大,不仅容易超出的sql长度限制,也会容易造成oom。使用预处理的方式进行批量插入是一种常见的优化方法,它可以显著提高插入操作的性能。

飞奔的屎壳郎 3171

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

SqlServer数据库批量插入数据报错

SqlServer数据库批量插入数据时,为什么会报错?本篇文章给出答案。

casually的博客 421

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

批量与分段插入insert数据到数据库中

问题现象: 项目中的一个程序,其中包括了插入数据库的逻辑,但由于是单条数据插入,所以入库就很慢,利用批量插入提高速度。 问题分析: 1. 插入慢 单数据插入数据库很慢,因为需要多次访问数据库,而批量插入则只需要访问一次数据库即可,所以会快很多。 2. 数量限制 所有的数据库(Oracle,Mysql,SQLServer,Postgresql,SQLite等等)都有自己的入库数量限制,这个就需要测试和验证得知了! 解决方法: 应用: 1. 批量入库方法 First : impor.

weixin_42585386的博客 1567

TDengine 如何批量插入?

【本文正在参与 “拥抱开源 | 涛思数据 TDengine有奖征稿】拥抱开源 涛思数据 TDengine有奖征稿活动-优快云 链接:https://marketing.youkuaiyun.com/p/0ada836ca30caa924b9baae0fd33857c 文章目录正常插入批量插入解决错误查询官方文档常见问题官方文档连接器官方文档高效写入数据官方文档最终结论修改后的代码       最近在使用涛思旗下tdengine数据库的时候,因为需求,需要

慢慢来 6884
上一篇: 设置集群密码
下一篇: JVM系列三:JVM参数设置、分析
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值