快速批量导入庞大数据到SQL SERVER数据库(ADO.NET)
原文地址:http://www.cnblogs.com/chenxizhang/archive/2008/11/11/1331060.html
如果你需要在程序中批量插入成千上万行的数据,你会怎么编写代码呢?最近在帮朋友调优这个的时候,总结了几种方法,并对其进行比较。
大概的界面如下,我模拟了一个客户资料表.
数据我是放在一个XML文件的,大约6734行。类似下面的格式
<?xml version="1.0" encoding="utf-8" ?>
<root>
<Customers>
<CustomerID>ALFKI</CustomerID>
<CompanyName>Sina</CompanyName>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
<Address>Obere Str. 57</Address>
<City>Berlin</City>
<PostalCode>12209</PostalCode>
<Country>Germany</Country>
<Phone>030-0074321</Phone>
<Fax>030-0076545</Fax>
</Customers>
<Customers>
<CustomerID>ANATR</CustomerID>
<CompanyName>Ana Trujillo Emparedados y helados</CompanyName>
<ContactName>Ana Trujillo</ContactName>
<ContactTitle>Owner</ContactTitle>
<Address>Avda. de la Constitución 2222</Address>
<City>México D.F.</City>
<PostalCode>05021</PostalCode>
<Country>Mexico</Country>
<Phone>(5) 555-4729</Phone>
<Fax>(5) 555-3745</Fax>
</Customers>
<Customers>
<CustomerID>ANTON</CustomerID>
<CompanyName>Antonio Moreno Taquería</CompanyName>
<ContactName>Antonio Moreno</ContactName>
<ContactTitle>Owner</ContactTitle>
<Address>Mataderos 2312</Address>
<City>México D.F.</City>
<PostalCode>05023</PostalCode>
<Country>Mexico</Country>
<Phone>(5) 555-3932</Phone>
</Customers>
</root>
下面首先在服务器稍微准备一下环境
USE [tempdb]
GO SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Customers](
[CustomerID] [nchar](5) NOT NULL,
[CompanyName] [nvarchar](40) NOT NULL,
[ContactName] [nvarchar](30) NULL,
[ContactTitle] [nvarchar](30) NULL,
[Address] [nvarchar](60) NULL,
[City] [nvarchar](15) NULL,
[Region] [nvarchar](15) NULL,
[PostalCode] [nvarchar](10) NULL,
[Country] [nvarchar](15) NULL,
[Phone] [nvarchar](24) NULL,
[Fax] [nvarchar](24) NULL
) ON [PRIMARY] CREATE PROCEDURE [dbo].[usp_InsertCustomer]
@CustomerID nchar(5),
@CompanyName nvarchar(40),
@ContactName nvarchar(30),
@ContactTitle nvarchar(30),
@Address nvarchar(60),
@City nvarchar(15),
@Region nvarchar(15),
@PostalCode nvarchar(10),
@Country nvarchar(15),
@Phone nvarchar(24),
@Fax nvarchar(24)
AS SET NOCOUNT ON INSERT INTO [dbo].[Customers] (
[CustomerID],
[CompanyName],
[ContactName],
[ContactTitle],
[Address],
[City],
[Region],
[PostalCode],
[Country],
[Phone],
[Fax]
) VALUES (
@CustomerID,
@CompanyName,
@ContactName,
@ContactTitle,
@Address,
@City,
@Region,
@PostalCode,
@Country,
@Phone,
@Fax
)
我们在tempdb中创建了一个表和一个存储过程
首先,我们把数据加载到一个DataSet
DataSet ds = new DataSet();
private void btLoadData_Click(object sender, EventArgs e)
{
string dataFile = "CustomersData.xml";
ds.ReadXml(dataFile);
bindingSource1.DataSource = ds;
bindingSource1.DataMember = "Customers";
dataGridView1.DataSource = bindingSource1; }
然后,我们第一个测试代码是遍历这个DataSet,每一行提交一次
private string GetConnectionString()
{
return "server=(local);database=tempdb;integrated security=true;";
}
/// <summary>
/// 直接遍历,一个一个的提交给服务器。时间为265毫秒左右
/// 每一行都需要写日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btOneByOne_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(GetConnectionString());
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "usp_InsertCustomer";
cmd.CommandType = CommandType.StoredProcedure;
conn.Open(); TimeSpan startTime = System.Diagnostics.Process.GetCurrentProcess().UserProcessorTime; foreach (DataRow row in ds.Tables[0].Rows)
{
cmd.Parameters.Clear();
SqlParameter[] param = new SqlParameter[]{
new SqlParameter("@CustomerID",row[0].ToString()),
new SqlParameter("@CompanyName",row[1].ToString()),
new SqlParameter("@ContactName",row[2].ToString()),
new SqlParameter("@ContactTitle",row[3].ToString()),
new SqlParameter("@Address",row[4].ToString()),
new SqlParameter("@City",row[5].ToString()),
new SqlParameter("@Region",row[6].ToString()),
new SqlParameter("@PostalCode",row[7].ToString()),
new SqlParameter("@Country",row[8].ToString()),
new SqlParameter("@Phone",row[9].ToString()),
new SqlParameter("@Fax",row[10].ToString())
};
cmd.Parameters.AddRange(param);
cmd.ExecuteNonQuery();
}
conn.Close(); TimeSpan duration = System.Diagnostics.Process.GetCurrentProcess().UserProcessorTime.Subtract(startTime);
MessageBox.Show("已经全部插入成功,所用时间为" + duration.Milliseconds.ToString() + "毫秒");
}
接下来,我们使用ADO.NET内置的一个DataAdapter来提交
/// <summary>
/// 这是使用Adapter的方式,其实还是遍历,而且语法也没有简单
/// 同时,速度甚至更慢。时间为650毫秒左右
/// 每一行都需要写日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btUseAdapter_Click(object sender, EventArgs e)
{
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.AcceptChangesDuringUpdate = false;//为了演示目的,把这个开关关掉,以免它在更新完成后把数据集标记为未更改
adapter.UpdateBatchSize = 10;//这个好像也没有什么用 SqlConnection conn = new SqlConnection(GetConnectionString());
SqlCommand insertCommand = conn.CreateCommand();
insertCommand.CommandText = "usp_InsertCustomer";
insertCommand.CommandType = CommandType.StoredProcedure; insertCommand.UpdatedRowSource = UpdateRowSource.None; insertCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");
insertCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 40, "CompanyName");
insertCommand.Parameters.Add("@ContactName", SqlDbType.NVarChar, 30, "ContactName");
insertCommand.Parameters.Add("@ContactTitle", SqlDbType.NVarChar, 30, "ContactTitle");
insertCommand.Parameters.Add("@Address", SqlDbType.NVarChar, 60, "Address");
insertCommand.Parameters.Add("@City", SqlDbType.NVarChar, 15, "City");
insertCommand.Parameters.Add("@Region", SqlDbType.NVarChar, 15, "Region");
insertCommand.Parameters.Add("@PostalCode", SqlDbType.NVarChar, 10, "PostalCode");
insertCommand.Parameters.Add("@Country", SqlDbType.NVarChar, 15, "Country");
insertCommand.Parameters.Add("@Phone", SqlDbType.NVarChar, 24, "Phone");
insertCommand.Parameters.Add("@Fax", SqlDbType.NVarChar, 24, "Fax"); adapter.InsertCommand = insertCommand;
TimeSpan startTime = System.Diagnostics.Process.GetCurrentProcess().UserProcessorTime;
adapter.Update(ds,"Customers");
TimeSpan duration = System.Diagnostics.Process.GetCurrentProcess().UserProcessorTime.Subtract(startTime);
MessageBox.Show("已经全部插入成功,所用时间为" + duration.Milliseconds.ToString() + "毫秒"); }
最后,我们找到了最快的方法
/// <summary>
/// 使用新的API,批量导入,这个速度很快,大约26毫秒,很显然,这种方式只写一次日志,不会为每一行写日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btBCP_Click(object sender, EventArgs e)
{
using (SqlConnection conn = new SqlConnection(GetConnectionString()))
{
SqlBulkCopy bcp = new SqlBulkCopy(conn);
bcp.DestinationTableName = "Customers";
bcp.BatchSize = 100;//这是批尺寸可以调整
for (int i = 0; i < 11; i++)
{
bcp.ColumnMappings.Add(i, i);
}
TimeSpan startTime = System.Diagnostics.Process.GetCurrentProcess().UserProcessorTime;
conn.Open();
bcp.WriteToServer(ds.Tables[0]);
TimeSpan duration = System.Diagnostics.Process.GetCurrentProcess().UserProcessorTime.Subtract(startTime);
MessageBox.Show("已经全部插入成功,所用时间为" + duration.Milliseconds.ToString() + "毫秒"); }
}
还有一种办法是通过在服务器OPENXML,因为XML反复处理效率很差,所以就没有测试了,可以断定它肯定比其他几种还要慢。
另外提示一下,如果不用编程的方式,那么有其他三个可能的途径去做这个事情
1. BCP工具(这是一个命令行,可以做导入和导出,不过来源文件如果不规范,那么可能很费劲)
2. BULK INSERT语句(这是一个T-SQL语句,只能做导入,我们上面使用的SQLBULKCopy应该和他很类似)
3. XML Bulk Load(这是一套COM的对象模型,适合导入XML文档)
还有,在做大量的数据导入和导出时,可以考虑微软为SQL Server配套的SSIS(Integration Service)
快速批量导入庞大数据到SQL SERVER数据库(ADO.NET)的更多相关文章
- 将DataTable 数据插入 SQL SERVER 数据库
原文:将DataTable 数据插入 SQL SERVER 数据库 以下提供3中方式将DataTable中的数据插入到SQL SERVER 数据库: 一:使用sqlcommand.executenon ...
- 【转】PowerShell 连接SQL Server 数据库 - ADO.NET
转至:http://www.pstips.net/connect-sql-database.html PowerShell 通过ADO.NET连接SQL Server数据库,并执行SQL脚本.工作中整 ...
- sql server 小技巧(1) 导入csv数据到sql server
1. 右击 DataBaseName,选择 Tasks->Import Data 2. 选择数据源: Flat File Source , 选择一个csv文件 Advance: 选择所有的列,改 ...
- C#快速导入海量XML数据至SQL Server数据库
#region 将Xml中的数据读到Dataset中,然后用SqlBulkCopy类把数据copy到目的表中using (XmlTextReader xmlReader = new XmlTextRe ...
- Excel导入数据到Sql server 中出错:“文本被截断,或者一个或多个字符在目标代码页中没有匹配项”
从Excel导入数据到Sql server 时,由于表中的数据有的很长,导入时出现如下错误(如果数据不是很长,255内以内,则不会出现错误): 出错原因: SQL Server的导入导出为了确定数据表 ...
- 转:SQL SERVER数据库中实现快速的数据提取和数据分页
探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分页.以下代码说明了我们实例中数据库的“红头文件”一表的部分数据结构: CREATE TABLE [dbo]. ...
- 极限挑战—C#100万条数据导入SQL SERVER数据库仅用4秒 (附源码)
原文:极限挑战-C#100万条数据导入SQL SERVER数据库仅用4秒 (附源码) 实际工作中有时候需要把大量数据导入数据库,然后用于各种程序计算,本实验将使用5中方法完成这个过程,并详细记录各种方 ...
- 图解如何 将Excel里的数据导入到sql server数据库中
项目中,经常会碰到如何将Excel里的数据导入到sql server中的问题. 下面,图解如何实现导入Excel中的数据到sql server 2008 R2: Excel截图如下: 查询pub数据库 ...
- Excel表数据导入Sql Server数据库中
Excel表数据导入Sql Server数据库的方法很多,这里只是介绍了其中一种: 1.首先,我们要先在test数据库中新建一个my_test表,该表具有三个字段tid int类型, tname nv ...
随机推荐
- 【剑指offer】面试题37:两个链表的第一个公共结点
题目: 输入两个链表,找出它们的第一个公共结点. 思路: 由链表的定义知是单链表.对于单链表,如果两个链表有公共结点,则两个链表必然是像Y型相交.则先计算出各个链表的长度,让长链表的头指针先走多出来的 ...
- MongoDB命令行操作
本文专门介绍MongoDB的命令行操作.其实,这些操作在MongoDB官网提供的Quick Reference上都有,但是英文的,为了方便,这里将其稍微整理下,方便查阅. 这里用来做测试的是远端(10 ...
- git hub 资料汇总
tobecrazy Selenium automation test framework https://github.com/tobecrazy/Demo Smartphone Test F ...
- AllocConsole
#include<iostream> using namespace std; AllocConsole(); freopen("CONIN$", "r+t& ...
- web前端代码规范——css代码规范
Bootstrap CSS编码规范 语法 用两个空格来代替制表符(tab) -- 这是唯一能保证在所有环境下获得一致展现的方法. 为选择器分组时,将单独的选择器单独放在一行. 为了代码的易读性,在每个 ...
- c++读取ccbi
loader类文件: 需要定义CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(ButtonTestLayerLoader, loader); 这个宏定义是定义静态的l ...
- Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类
前言 近期做换肤功能,由于换肤程度较高,受限于平台本身,实现起来较复杂,暂时搁置了该功能,但也积累了一些经验,将分两篇文章来写这部分的内容,欢迎交流! 关键字:Android动态加载 声明 欢迎转载, ...
- ant学习(1)
路径:/home/framework_Study/springinAction/webRoot/WEB-INF <?xml version="1.0" encoding=&q ...
- openssl 证书请求和自签名命令req详解
1.密钥.证书请求.证书概要说明 在证书申请签发过程中,客户端涉及到密钥.证书请求.证书这几个概念,初学者可能会搞不清楚三者的关系,网上有的根据后缀名来区分三者,更让人一头雾水.我们以申请证书的流程说 ...
- C#之获取本地IP地址
最近协助一个项目解决了一个获取IP地址的问题,手机客户端与WebService进行通讯,然后WebService通过TCP通讯把指令传递到另一台PC机上.在测试的过程中,总是会出现WebService ...