Sql Server 2012批量处理注意!!

SQL Server 2008中SQL应用系列--目录索引

今天在做一个案例演示时,在SQL Server 2012中使用Insert语句插入1万条数据,结果遇到了一个奇怪的现象,现将过程分享出来,以供有兴趣的同学参考。


附:我的测试环境为:
SQL Server 2012,命名实例

Microsoft SQL Server 2012 - 11.0.2100.60 (Intel X86) 
Feb 10 2012 19:13:17 
Copyright (c) Microsoft Corporation
Enterprise Edition on Windows NT 6.0 <X86> (Build 6002: Service Pack 2)


创建示例数据库

  1. IF OBJECT_ID('DemoPager2012'IS NOT NULL  
  2. DROP DataBase DemoPager2012  
  3. GO  
  4.   
  5. CREATE Database DemoPager2012  
  6. GO  
  7.   
  8. USE DemoPager2012  
  9. GO  
示例表,该表只有四个字段。

  1. /*  
  2. Setup script to create the sample table and fill it with  
  3. sample data.  
  4. */  
  5. IF OBJECT_ID('Customers','U'IS NOT NULL  
  6. DROP TABLE Customers  
  7.   
  8. CREATE TABLE Customers ( CustomerID INT primary key identity(1,1),  
  9. CustomerNumber CHAR(4),  
  10. CustomerName VARCHAR(50),  
  11. CustomerCity VARCHAR(20) )  
  12. GO  
现在展示批量插入10000条数据到该表中,语句如下:

  1. TRUNCATE table Customers  
  2. GO  
  3.   
  4. ----清除干扰查询  
  5. DBCC DROPCLEANBUFFERS  
  6. DBCC FREEPROCCACHE  
  7.   
  8. SET STATISTICS IO ON;  
  9. SET STATISTICS TIME ON;  
  10. GO  
  11.   
  12. DECLARE @d Datetime  
  13. SET @d=getdate();  
  14.   
  15. declare @i int=1  
  16. while @i<=10000  
  17. begin  
  18. INSERT INTO Customers (CustomerNumber, CustomerName,  
  19. CustomerCity)  
  20. SELECT REPLACE(STR(@i, 4), ' ''0'),'Customer ' + STR(@i,6),  
  21. CHAR(65 + (@i % 26)) + '-City'  
  22. set @i=@i+1  
  23. end  
  24.   
  25. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  26.   
  27. SET STATISTICS IO OFF ;  
  28. SET STATISTICS TIME OFF;  
  29. GO  

该插入语句在SQL Server 2008 r2版本和SQL Server 2012版本中,测试结果如下:

邀月工作室

 

 

令我惊讶的是,SQL Server 2012居然耗时达到5分多钟,而SQL Server 2008R2版,只需要大约6秒钟。更令人费解的是:查询的I/O统计和elapsed time,在这两个版本中几乎一样。对此异象,我只能理解为每次Insert时的毫秒级精度可能不足以度量该次操作带来的细小差距,然而累积起来就非常可观了。

解决方案一:使用 Set NoCount On,效果立竿见影

  1. TRUNCATE table Customers  
  2. GO  
  3.   
  4. ----清除干扰查询  
  5. DBCC DROPCLEANBUFFERS  
  6. DBCC FREEPROCCACHE  
  7.   
  8. SET STATISTICS IO ON;  
  9. SET STATISTICS TIME ON;  
  10. GO  
  11.   
  12. DECLARE @d Datetime  
  13. SET @d=getdate();  
  14. set nocount on  
  15. declare @i int=1  
  16. while @i<=10000  
  17. begin  
  18. INSERT INTO Customers (CustomerNumber, CustomerName,  
  19. CustomerCity)  
  20. SELECT REPLACE(STR(@i, 4), ' ''0'),'Customer ' + STR(@i,6),  
  21. CHAR(65 + (@i % 26)) + '-City'  
  22. set @i=@i+1  
  23. end  
  24.   
  25. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  26.   
  27. SET STATISTICS IO OFF ;  
  28. SET STATISTICS TIME OFF;  
  29. GO  

邀月工作室

Set NoCount On(http://msdn.microsoft.com/zh-cn/library/ms189837.aspx)的作用:使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息。这在批量插入时将显著提高性能。至于 本例中,为什么SQL Server 2008 R2版中却不受该开关影响,希望知道的同学不吝赐教,非常感谢。

 

改进解决方案二:使用 Set NoCount On+Transaction

  1. TRUNCATE table Customers  
  2. GO  
  3.   
  4. ----清除干扰查询  
  5. DBCC DROPCLEANBUFFERS  
  6. DBCC FREEPROCCACHE  
  7.   
  8.    
  9.   
  10. SET STATISTICS IO ON;  
  11. SET STATISTICS TIME ON;  
  12. GO  
  13.   
  14. DECLARE @d Datetime  
  15. SET @d=getdate();  
  16. set nocount on  
  17. declare @i int=1  
  18. BEGIN TRANSACTION  
  19. while @i<=10000  
  20. begin  
  21. INSERT INTO Customers (CustomerNumber, CustomerName,  
  22. CustomerCity)  
  23. SELECT REPLACE(STR(@i, 4), ' ''0'),'Customer ' + STR(@i,6),  
  24. CHAR(65 + (@i % 26)) + '-City'  
  25. set @i=@i+1  
  26. end  
  27. COMMIT  
  28. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  29.   
  30. SET STATISTICS IO OFF ;  
  31. SET STATISTICS TIME OFF;  
  32. GO  

邀月工作室

解决方案三:使用递归CTE插入

  1. TRUNCATE table Customers  
  2. GO  
  3.   
  4. DBCC DROPCLEANBUFFERS  
  5. DBCC FREEPROCCACHE  
  6.   
  7. SET STATISTICS IO ON;  
  8. SET STATISTICS TIME ON;  
  9. GO  
  10.   
  11. DECLARE @d Datetime  
  12. SET @d=getdate();  
  13.   
  14. /*****运用CTE递归插入,速度较快,邀月注***********************/  
  15. WITH Seq (num,CustomerNumber, CustomerName, CustomerCity) AS  
  16. (SELECT 1,cast('0000'as CHAR(4)),cast('Customer 0' AS NVARCHAR(50)),cast('X-City' as NVARCHAR(20))  
  17. UNION ALL  
  18. SELECT num + 1,Cast(REPLACE(STR(num, 4), ' ''0'AS CHAR(4)),  
  19. cast('Customer ' + STR(num,6) AS NVARCHAR(50)),  
  20. cast(CHAR(65 + (num % 26)) + '-City' AS NVARCHAR(20))  
  21. FROM Seq  
  22. WHERE num <= 10000  
  23. )  
  24. INSERT INTO Customers (CustomerNumber, CustomerName, CustomerCity)  
  25. SELECT CustomerNumber, CustomerName, CustomerCity  
  26. FROM Seq  
  27. OPTION (MAXRECURSION 0)  
  28.   
  29. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  30.   
  31. SET STATISTICS IO OFF ;  
  32. SET STATISTICS TIME OFF;  
  33. GO  

邀月工作室

 

小结:SQL Server 2012中批量插入数据时,请记得Set NoCount ON,并尽可能加上Transaction,当然,推荐使用CTE,这可能会带来性能上的巨大提升。

 

邀月补充:

后来与微软亚太工程师多次沟通,得出初步结论:

在不打开“set nocount on”时,SSMS 2012与SSMS 2008r2版本的UI在执行效率上可能有极大差异,而与SQL Server引擎没有明显相关。



http://blog.youkuaiyun.com/downmoon/article/details/7475841

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值