`
netxdiy
  • 浏览: 679156 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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)


创建示例数据库

IF OBJECT_ID('DemoPager2012') IS NOT NULL
DROP DataBase DemoPager2012
GO

CREATE Database DemoPager2012
GO

USE DemoPager2012
GO

示例表,该表只有四个字段。

/*
Setup script to create the sample table and fill it with
sample data.
*/
IF OBJECT_ID('Customers','U') IS NOT NULL
DROP TABLE Customers

CREATE TABLE Customers ( CustomerID INT primary key identity(1,1),
CustomerNumber CHAR(4),
CustomerName VARCHAR(50),
CustomerCity VARCHAR(20) )
GO

现在展示批量插入10000条数据到该表中,语句如下:

TRUNCATE table Customers
GO

----清除干扰查询
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

DECLARE @d Datetime
SET @d=getdate();

declare @i int=1
while @i<=10000
begin
INSERT INTO Customers (CustomerNumber, CustomerName,
CustomerCity)
SELECT REPLACE(STR(@i, 4), ' ', '0'),'Customer ' + STR(@i,6),
CHAR(65 + (@i % 26)) + '-City'
set @i=@i+1
end

select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

SET STATISTICS IO OFF ;
SET STATISTICS TIME OFF;
GO

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

邀月工作室

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

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

TRUNCATE table Customers
GO

----清除干扰查询
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

DECLARE @d Datetime
SET @d=getdate();
set nocount on
declare @i int=1
while @i<=10000
begin
INSERT INTO Customers (CustomerNumber, CustomerName,
CustomerCity)
SELECT REPLACE(STR(@i, 4), ' ', '0'),'Customer ' + STR(@i,6),
CHAR(65 + (@i % 26)) + '-City'
set @i=@i+1
end

select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

SET STATISTICS IO OFF ;
SET STATISTICS TIME OFF;
GO

邀月工作室

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

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

TRUNCATE table Customers
GO

----清除干扰查询
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

 

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

DECLARE @d Datetime
SET @d=getdate();
set nocount on
declare @i int=1
BEGIN TRANSACTION
while @i<=10000
begin
INSERT INTO Customers (CustomerNumber, CustomerName,
CustomerCity)
SELECT REPLACE(STR(@i, 4), ' ', '0'),'Customer ' + STR(@i,6),
CHAR(65 + (@i % 26)) + '-City'
set @i=@i+1
end
COMMIT
select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

SET STATISTICS IO OFF ;
SET STATISTICS TIME OFF;
GO

邀月工作室

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

TRUNCATE table Customers
GO

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

DECLARE @d Datetime
SET @d=getdate();

/*****运用CTE递归插入,速度较快,邀月注***********************/
WITH Seq (num,CustomerNumber, CustomerName, CustomerCity) AS
(SELECT 1,cast('0000'as CHAR(4)),cast('Customer 0' AS NVARCHAR(50)),cast('X-City' as NVARCHAR(20))
UNION ALL
SELECT num + 1,Cast(REPLACE(STR(num, 4), ' ', '0') AS CHAR(4)),
cast('Customer ' + STR(num,6) AS NVARCHAR(50)),
cast(CHAR(65 + (num % 26)) + '-City' AS NVARCHAR(20))
FROM Seq
WHERE num <= 10000
)
INSERT INTO Customers (CustomerNumber, CustomerName, CustomerCity)
SELECT CustomerNumber, CustomerName, CustomerCity
FROM Seq
OPTION (MAXRECURSION 0)

select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

SET STATISTICS IO OFF ;
SET STATISTICS TIME OFF;
GO


邀月工作室

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

邀月补充:

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

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

邀月注:本文版权由邀月和CSDN共同所有,转载请注明出处。
助人等于自助! 3w@live.cn




分享到:
评论

相关推荐

    sql下三种批量插入数据的方法

    第二种方法使用的是SqlBulkCopy,使您可以用其他源的数据有效批量加载 SQL Server 表;第三种使用的方法是sql server中的表值参数方法,表值参数是 SQL Server 2008 中的新参数类型。表值参数是使用用户定义的表类型...

    SQLServer用存储过程实现插入更新数据示例

    主要介绍了SQLServer如何用存储过程实现插入更新数据,需要的朋友可以参考下

    SQL21日自学通

    示例表及数据394 一个简单的PL/SQL 语句块395 又一个程序398 存储过程包和触发机制403 总结406 问与答407 校练场407 练习407 第19 天TRANSACT-SQL 简介408 目标408 TRANSACT-SQL 概貌408 对ANSI SQL 的扩展408 谁...

    MySQL5 权威指南第3版中文版_part1

     19.5 转换器:从Microsoft SQL Server到MySQL  19.6 VBMySQLDirect  第20章 Visual Basic .NET和C#  20.1 ADO .NET与MySQL之间的通信  20.2 编程技巧  20.3 示例:把新图书记录存入mylibrary数据库  20.4 ...

    MySQL 5权威指南(第3版) 中文版 下载地址

     19.5 转换器:从Microsoft SQL Server到MySQL  19.6 VBMySQLDirect  第20章 Visual Basic .NET和C#  20.1 ADO .NET与MySQL之间的通信  20.2 编程技巧  20.3 示例:把新图书记录存入mylibrary数据库  ...

    Access 2000数据库系统设计(PDF)---001

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库 相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动...

    Access 2000数据库系统设计(PDF)---002

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库 相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动...

    Access 2000数据库系统设计(PDF)---018

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---003

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库 相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动...

    Access 2000数据库系统设计(PDF)---011

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---020

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---009

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库 相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动...

    Access 2000数据库系统设计(PDF)---012

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---015

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---027

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---025

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---026

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    Access 2000数据库系统设计(PDF)---029

    101.6 浏览和编辑子数据表中的相关记录 111.7 使Jet和SQL Server 7.0/MSDE数据库相一致 111.8 Access在2000年问题上的改进 121.8.1 四位数年份选项设置 121.8.2 数据库窗口 131.8.3 窗体和报表 141.8.4 名称自动更正...

    MybatisGeneratorPlus.zip

    扩展 Mybatis-Generator,自动生成支持 Oracle、Mysql、Sqlserver 分页查询和批量插入操作的自动代码,支持从 Mapper 接口读取数据源名称;支持 Oracle 使用 SEQUENCE 实现自增主键:需要事先建立好表主键对应的...

Global site tag (gtag.js) - Google Analytics