SQL批量新增数据(后续)

6 篇文章 0 订阅
5 篇文章 0 订阅

今天大年初七,新的一年的打工生活又开始了,先祝大家工作顺利!学业进步!

今天主要是处理当初遗留问题的一篇博客

可查看博客 : SQL批量新增数据  了解前因 ~~

在上一次的批量中,在数据量较大的时候,会导致insert非常慢,出现假死状态等,具体可看上边连接

对于这个问题,在当初出现后不久就已经有解决方案了,但是一直没有合适的时间进行整理

问题原因:I/O

简单说可以把insert作为守门人开合一扇门,数据作为一个人,我们原方法做的就是进一个人,就开一次门,然后在开合的时候,那个开门的人就会累

我们也可以拿核算检测做类比:最开始的时候我们都是一人一次的检查,每个人都需要一份试剂,这在早期也是很慢的,假如是一个人一直做,那就会存在效率变低,所以要轮班保证效率,但是我们执行SQL的时候,是没有可以轮班的,等于是一个人在把百万人的核算检测做了(一次处理多笔)。后边技术提升了,我们可以把检测结果这条路,做成10人合到一个试剂检查,等于提高了10倍的效率,再者,我们不止一个人,我们有众多的医护人员,志愿者等,又加快了获取数据了效率(多线程)

由上结论,我们在SQL上,今天使用的方案1使用的就是一次处理多笔这步流程(多线程得使用程序)

因目前技术有限,这也就只是方案1,后续或许会有更好的方法,也会更新进来,或者添加链接

进入方案1的正题:

1、新建数据库表

--BatchAddData_20210218
--新加一个表,用来测试本次的批量新增数据
 if  NOT  exists   (select   *   from   dbo.sysobjects   where   id   =   object_id(N'[dbo].[BatchAddData_20210218]')   and   OBJECTPROPERTY(id,   N'IsUserTable')   =   1)    
  BEGIN
   CREATE TABLE [dbo].[BatchAddData_20210218](
	[ID] [int] IDENTITY(1,1) NOT NULL, --主键ID
	
	[CreationTime] [datetime] NULL,--创建时间
	[Remark][nvarchar](MAX) NULL --备注
) 
  END
  GO


  --select *from BatchAddData_20210218

2、先使用原方法做 测试

--批量数据
--循环添加数据
declare @i int --声明一个变量
set @i=1     --给变量赋值(初始化)
while @i<10   --循环插入
begin
	insert into BatchAddData_20210218 (CreationTime,Remark)
	values ( GETDATE(),'SQL批量新增[20200218]-第一轮');
set @i=@i+1
end

GO

2.1 结果

由图可见,数据较少的时候,执行还是非常的顺利的。

一百、一千、一万...百万的我就不在这 测试来了

3、使用新方法,上边是10条数据,那我把他分成2*5,也就是执行两个insert即可

--批量数据
--循环添加数据
declare @i int --声明一个变量
set @i=1     --给变量赋值(初始化)
while @i<=2   --循环插入
begin
	insert into BatchAddData_20210218 (CreationTime,Remark)
	values ( GETDATE(),'SQL批量新增[20200218]-第二轮:2*5')
	,( GETDATE(),'SQL批量新增[20200218]-第二轮:2*5')
	,( GETDATE(),'SQL批量新增[20200218]-第二轮:2*5')
	,( GETDATE(),'SQL批量新增[20200218]-第二轮:2*5')
	,( GETDATE(),'SQL批量新增[20200218]-第二轮:2*5')
	;
set @i=@i+1
end

GO

3.1 结果 

从上图图3可以直观的看到,10条数据在毫秒内就处理完成了,图1的总执行时间也缩小了近5倍。

4、思考

4.1 假如新方法这么好用,那我不是可以一次就把10条insert 了?答案肯定是可以的,但是假如又回到百万数据呢,又该如何?

5 处理百万数据

5.1 拆分 100*1000 或者 1000*1000,在处理SQL的时候,我们不可能把数据写的太死,这里至少在循环SQL时的SQL拼接得处理

5.2 测试1000


--批量数据(1000)
--循环添加数据
declare @i int --声明一个变量
set @i=1     --给变量赋值(初始化)
declare @j int --声明一个变量
set @j=1     --给变量赋值(初始化)

declare @execSQL nvarchar(max) --拼接SQL 
--set @execSQL ='insert into BatchAddData_20210218 (CreationTime,Remark)'     --给变量赋值(初始化)

while @i<=10   --循环插入
begin

--放入外循环
set @execSQL ='insert into BatchAddData_20210218 (CreationTime,Remark)'     --给变量赋值(初始化)



--------------内循环:拼接SQL ---------------------------------------
while @j<=10   --循环插入
begin
if(@j=1)
begin
set @execSQL +='values ( GETDATE(),''SQL批量新增[20200218]-第三轮:100*100'')'
	set @j=@j+1
end
if(@j!=1)
begin
set @execSQL +=', ( GETDATE(),''SQL批量新增[20200218]-第三轮:100*100'')'
	set @j=@j+1
end

end
---------------------------------------------------------------------

--print @execSQL
EXEC ( @execSQL )  --执行拼接好的SQL
set  @execSQL = '' --清除(可无)
set @j= 1;

set @i=@i+1
end

GO


5.2.1 结果 从结果看,第二和第四的时间一致,还是存在有误的可能性

5.3 优化

5.3.1 重新写批量SQL(为了效果)


--批量数据(1000)
--循环添加数据
declare @i int --声明一个变量
set @i=1     --给变量赋值(初始化)
declare @j int --声明一个变量
set @j=1     --给变量赋值(初始化)
declare @sum int --声明一个变量
set @sum=1     --给变量赋值(初始化)

declare @execSQL nvarchar(max) --拼接SQL 
--set @execSQL ='insert into BatchAddData_20210218 (CreationTime,Remark)'     --给变量赋值(初始化)


while @i<=10   --循环插入
begin

--放入外循环
set @execSQL ='insert into BatchAddData_20210218 (CreationTime,Remark)'     --给变量赋值(初始化)



--------------内循环:拼接SQL ---------------------------------------
while @j<=10   --循环插入



begin
if(@j=1)
begin
set @execSQL +=' values ( GETDATE(),'''+CONVERT(nvarchar(max),@sum)+'''+''第4轮,10*10'')'
	set @j=@j+1
	set @sum = @sum +1;
end
if(@j!=1)
begin
set @execSQL +=', ( GETDATE(),'''+CONVERT(nvarchar(max),@sum)+'''+''第4轮,10*10'')'
	set @j=@j+1
	set @sum = @sum +1;
end

--set @sum = @sum +1;
end
---------------------------------------------------------------------

--print @execSQL
EXEC ( @execSQL )      --执行拼接好的SQL
set  @execSQL = '' --清除(可无)
set @j= 1;

set @i=@i+1
end

GO

5.3.2 结果 :效果还是相对可以,那么,我们就开始测试百万数据情况

 

6、百万数据 测试

方案1 : 100*10000 ,失败,内循环超过1000

方案2 : 1000*1000  可行,但是数据库还是有点卡顿,最后一段时间是7秒刷新一次,一次外循环的时间

同样的,外循环处理数据达到一定量的时候,他也会变慢,从开始的1秒跳,到最后的7秒跳

但是数据量较大,还是没有等待全部执行(目前是10分钟33秒,113000笔数据,insert了11.3%的数据)

1%的占比应该是不可能的,可能是SQL Server 数据库最小单位就是1%吧。

方案3 : 10000*100 

在处理别的,没把握好时间,(目前是12分钟27秒,27400笔数据,insert了27.4%的数据)

相比于方案2,多使用了2分钟,但是数据量却是比方案2多了一倍多的数据量,物极必满,最大量1000的还是只最为最大使用,并不是最高效率的情况

方案4 :由上述的出,我们内循环的值还可以在100 - 1000内取值,像200,500,等,都可再测试,我这也就不再测试了

 

总的来说,还是没有达到我理想的速度,还有待提高。

同时,这个还可以做成存储过程,直接调用,也没啥参数。

拓展:

1、这里的数据还是限制于数据库,假如使用程序的话,使用多线程,开5-8-10个,速度理论提升了5-8-10倍,但是同样的高频率的IO,是否又是假死呢?

2、假如数据不是整数,是其他数,该如何?比如1234条数据?123456条数据?

3、是否存在一个已知总数,得出最优内外循环值的可能性?

....

我是一个人三座城
一个人生活在三座城市,过去、现在、将来.
期待你的关注!

 

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
SQL函数是指在SQL语句中可以执行的可重用的代码块。SQL函数可以用于从数据库中获取、加工、处理和转换数据。在SQL语句中,函数可以被当作一个值使用,形参是输入项,返回值可以是单个值、表格或者其他类型的结果集。 而批量新增数据则是指在一次操作中新增多条数据进入数据库中,从而减少单条数据添加的时间和提高效率。在实际业务中,需要对大量数据进行操作,单独添加一条数据的速度太慢,容易出错。所以,批量新增数据能够快速地将一组数据添加到数据库中。 如果需要将多行数据添加到数据库中,SQL函数中可以使用INSERT INTO语句加上VALUES将所有数据一次性添加到数据库中。例如,下面的SQL语句用批量新增数据的方法向一个学生表中插入多行数据: ``` INSERT INTO Students (Name, Age, Gender, Address) VALUES ('Tina', 20, 'Female', 'Beijing'), ('Mike', 22, 'Male', 'Shanghai'), ('Linda', 21, 'Female', 'Guangzhou'), ('Jack', 19, 'Male', 'Chengdu') ``` 这个SQL语句可以将四个学生的信息一次性添加到学生表中,从而减少数据库操作的次数,提高效率。这种方式适用于需要一次性新增多条数据的情况,对于较小规模的数据插入操作,可能没有太大的提升。需要根据实际情况选择是否使用此方式。 总之,SQL函数与批量新增数据数据库操作中两个常用的技术。SQL函数可以快速地从数据库中获取、处理和转换数据,而批量新增数据能够减少单条数据添加的时间和提高效率。在实际开发中,需要根据不同的业务需求选择合适的方式进行操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值