快速批量导入庞大数据到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 ...
随机推荐
- bzoj1178
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1178 看ppt http://wenku.baidu.com/link?url=dJv6LNm ...
- day49
几天没写了 这几天比较麻木呢 各种课程的再看 想买一直不舍得money 今天下定决心买了 这样我也静下心好好备战把 一天背的东西好多 政治和作文也是背了就忘记 尽力把 今天的买的课很悬乎 就不在这说了 ...
- win10 下安装、配置、启动mysql
1.下载http://dev.mysql.com/downloads/mysql/ 2.Community > MySQL Community Server 3.Other Downloads: ...
- jquery Tabs选项卡切换
效果: HTML部分: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
- EnableDocking
CFrameWnd::EnableDocking void EnableDocking(DWORD dwDockStyle); 參数: dwDockStyle 指定框架窗体的哪一边可作为控件条的停靠点 ...
- gcc/g++/make 编译信息带颜色输出
假设编译一个项目错误警告太多.很不好找,所以很希望输出信息能够带有颜色. 但是 gcc 4.9.0 之前的版本号并不支持,非常多情况下是不能替换编译器的,比方使用交叉编译器, 也能够使用 colorg ...
- js中indexof()简单使用
indexOf()方法返回某个指定的字符串值在字符串中首次出现的位置. stringObject.indexOf(searchvalue,fromindex):indexOf()方法对大小写敏感如果要 ...
- DEV GridControl 导出到Excel
SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Title = "导出Excel"; sa ...
- (转)sql语句中charindex的用法
假如你写过很多程序,你可能偶尔会碰到要确定字符或字符窜串否包含在一段文字中,在这篇文章中,我将讨论使用CHARINDEX和PATINDEX函数来搜索文字列和字符串.我将告诉你这两个函数是如何运转的,解 ...
- 网站全局js代码
这几天开始看公司的一套系统,整理的网站全局js代码 /*文件名:base.js功能说明:全站通用的全局变量及公用方法创建日期:2010-09-26*///引入jquery库文件document.wri ...