(转)SQL一次性插入大量数据

在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题。下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters)。

运行下面的脚本,建立测试数据库和表值参数。

[c-sharp] view plain copy

  1. --Create DataBase
  2. create database BulkTestDB;
  3. go
  4. use BulkTestDB;
  5. go
  6. --Create Table
  7. Create table BulkTestTable(
  8. Id int primary key,
  9. UserName nvarchar(32),
  10. Pwd varchar(16))
  11. go
  12. --Create Table Valued
  13. CREATE TYPE BulkUdt AS TABLE
  14. (Id int,
  15. UserName nvarchar(32),
  16. Pwd varchar(16))

下面我们使用最简单的Insert语句来插入100万条数据,代码如下:

[c-sharp] view plain copy

  1. Stopwatch sw = new Stopwatch();
  2. SqlConnection sqlConn = new SqlConnection(
  3. ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);//连接数据库
  4. SqlCommand sqlComm = new SqlCommand();
  5. sqlComm.CommandText = string.Format("insert into BulkTestTable(Id,UserName,Pwd)values(@p0,@p1,@p2)");//参数化SQL
  6. sqlComm.Parameters.Add("@p0", SqlDbType.Int);
  7. sqlComm.Parameters.Add("@p1", SqlDbType.NVarChar);
  8. sqlComm.Parameters.Add("@p2", SqlDbType.VarChar);
  9. sqlComm.CommandType = CommandType.Text;
  10. sqlComm.Connection = sqlConn;
  11. sqlConn.Open();
  12. try
  13. {
  14. //循环插入100万条数据,每次插入10万条,插入10次。
  15. for (int multiply = 0; multiply < 10; multiply++)
  16. {
  17. for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)
  18. {
  19. sqlComm.Parameters["@p0"].Value = count;
  20. sqlComm.Parameters["@p1"].Value = string.Format("User-{0}", count * multiply);
  21. sqlComm.Parameters["@p2"].Value = string.Format("Pwd-{0}", count * multiply);
  22. sw.Start();
  23. sqlComm.ExecuteNonQuery();
  24. sw.Stop();
  25. }
  26. //每插入10万条数据后,显示此次插入所用时间
  27. Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));
  28. }
  29. }
  30. catch (Exception ex)
  31. {
  32. throw ex;
  33. }
  34. finally
  35. {
  36. sqlConn.Close();
  37. }
  38. Console.ReadLine();

耗时图如下:

由于运行过慢,才插入10万条就耗时72390 milliseconds,所以我就手动强行停止了。

下面看一下使用Bulk插入的情况:

bulk方法主要思想是通过在客户端把数据都缓存在Table中,然后利用SqlBulkCopy一次性把Table中的数据插入到数据库

代码如下:

[c-sharp] view plain copy

  1. public static void BulkToDB(DataTable dt)
  2. {
  3. SqlConnection sqlConn = new SqlConnection(
  4. ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);
  5. SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConn);
  6. bulkCopy.DestinationTableName = "BulkTestTable";
  7. bulkCopy.BatchSize = dt.Rows.Count;
  8. try
  9. {
  10. sqlConn.Open();
  11. if (dt != null && dt.Rows.Count != 0)
  12. bulkCopy.WriteToServer(dt);
  13. }
  14. catch (Exception ex)
  15. {
  16. throw ex;
  17. }
  18. finally
  19. {
  20. sqlConn.Close();
  21. if (bulkCopy != null)
  22. bulkCopy.Close();
  23. }
  24. }
  25. public static DataTable GetTableSchema()
  26. {
  27. DataTable dt = new DataTable();
  28. dt.Columns.AddRange(new DataColumn[]{
  29. new DataColumn("Id",typeof(int)),
  30. new DataColumn("UserName",typeof(string)),
  31. new DataColumn("Pwd",typeof(string))});
  32. return dt;
  33. }
  34. static void Main(string[] args)
  35. {
  36. Stopwatch sw = new Stopwatch();
  37. for (int multiply = 0; multiply < 10; multiply++)
  38. {
  39. DataTable dt = Bulk.GetTableSchema();
  40. for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)
  41. {
  42. DataRow r = dt.NewRow();
  43. r[0] = count;
  44. r[1] = string.Format("User-{0}", count * multiply);
  45. r[2] = string.Format("Pwd-{0}", count * multiply);
  46. dt.Rows.Add(r);
  47. }
  48. sw.Start();
  49. Bulk.BulkToDB(dt);
  50. sw.Stop();
  51. Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));
  52. }
  53. Console.ReadLine();
  54. }

耗时图如下:

可见,使用Bulk后,效率和性能明显上升。使用Insert插入10万数据耗时72390,而现在使用Bulk插入100万数据才耗时17583。

最后再看看使用表值参数的效率,会另你大为惊讶的。

表值参数是SQL Server 2008新特性,简称TVPs。对于表值参数不熟悉的朋友,可以参考最新的book online,我也会另外写一篇关于表值参数的博客,不过此次不对表值参数的概念做过多的介绍。言归正传,看代码:

[c-sharp] view plain copy

  1. public static void TableValuedToDB(DataTable dt)
  2. {
  3. SqlConnection sqlConn = new SqlConnection(
  4. ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);
  5. const string TSqlStatement =
  6. "insert into BulkTestTable (Id,UserName,Pwd)" +
  7. " SELECT nc.Id, nc.UserName,nc.Pwd" +
  8. " FROM @NewBulkTestTvp AS nc";
  9. SqlCommand cmd = new SqlCommand(TSqlStatement, sqlConn);
  10. SqlParameter catParam = cmd.Parameters.AddWithValue("@NewBulkTestTvp", dt);
  11. catParam.SqlDbType = SqlDbType.Structured;
  12. //表值参数的名字叫BulkUdt,在上面的建立测试环境的SQL中有。
  13. catParam.TypeName = "dbo.BulkUdt";
  14. try
  15. {
  16. sqlConn.Open();
  17. if (dt != null && dt.Rows.Count != 0)
  18. {
  19. cmd.ExecuteNonQuery();
  20. }
  21. }
  22. catch (Exception ex)
  23. {
  24. throw ex;
  25. }
  26. finally
  27. {
  28. sqlConn.Close();
  29. }
  30. }
  31. public static DataTable GetTableSchema()
  32. {
  33. DataTable dt = new DataTable();
  34. dt.Columns.AddRange(new DataColumn[]{
  35. new DataColumn("Id",typeof(int)),
  36. new DataColumn("UserName",typeof(string)),
  37. new DataColumn("Pwd",typeof(string))});
  38. return dt;
  39. }
  40. static void Main(string[] args)
  41. {
  42. Stopwatch sw = new Stopwatch();
  43. for (int multiply = 0; multiply < 10; multiply++)
  44. {
  45. DataTable dt = TableValued.GetTableSchema();
  46. for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)
  47. {
  48. DataRow r = dt.NewRow();
  49. r[0] = count;
  50. r[1] = string.Format("User-{0}", count * multiply);
  51. r[2] = string.Format("Pwd-{0}", count * multiply);
  52. dt.Rows.Add(r);
  53. }
  54. sw.Start();
  55. TableValued.TableValuedToDB(dt);
  56. sw.Stop();
  57. Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));
  58. }
  59. Console.ReadLine();
  60. }

耗时图如下:

比Bulk还快5秒。

时间: 2024-10-14 05:47:38

(转)SQL一次性插入大量数据的相关文章

SQL一次性插入大量数据

在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters). 运行下面的脚本,建立测试数据库和表值参数. [c-sharp] view plain copy --Create DataBase create database BulkTestDB; go use BulkTe

SQL Server插入中文数据后出现乱码

原文:SQL Server插入中文数据后出现乱码 今天在做项目的过程中遇到如标题的问题,情况如下图: 数据库使用的是SQL Server2012版本,创建表的脚本如下: CREATE TABLE [dbo].[Type](  [TypeId] INT NOT NULL PRIMARY KEY,     [TypeName] NVARCHAR(50)NOT NULL,     [Description] NVARCHAR(255) NULL,     [CategoryId] INT NOT NU

Java 向SQL Server插入文件数据

package sqlserver; import java.util.Date; import java.util.UUID; import java.text.SimpleDateFormat; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOut

数据库一次性插入10w条数据,怎么插入效率快

在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题 下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters). bulk方法主要思想是通过在客户端把数据都缓存在Table中,然后利用SqlBulkCopy一次性把Table中的数据插入到数据库 代码如下: public static void BulkToDB(DataTab

sql - 批量插入数据

直接构造 insert into t (c1, c2, c3) values (1, 1, 1), (2, 2, 2) 使用UNION insert into t (c1, c2, c3) (select a1, a2, a3) union all (select b1, b2, b3) 利用查询结果 insert into t (c1, c2, c3) (select a1, a2, a3 from t2) sql - 批量插入数据,布布扣,bubuko.com

SQL Server中中数据行批量插入脚本的存储实现

看到博友SQL Server MVP桦仔的一篇博文“将表里的数据批量生成INSERT语句的存储过程的实现”.我仔细看来博文中的两个存储代码,自我感觉两个都不太满意,都是生成的单行模式的插入,数据行稍微大些性能会受影响的.所在公司本来就存在第二个版本的类似实现,但是是基于多行模式的,还是需要手工添加UNAION ALL来满足多行模式的插入.看到这边博文和基于公司数据行批量脚本的存储的确定,这次改写和增强该存储的功能. 本存储运行于SQL Server 2005或以上版本,T-SQL代码如下: 1

SQL 如何在自增列插入指定数据

SQL Server  中数据表往往会设置自增列,常见的比如说 首列的ID列. 往数据表插入新数据的时候,自增列是跳过的,无需插入即会按照设置的自增规则进行列增长.那么,如果我们想往自增列插入我们指定的数据时该怎么做呢?  一:建立一张简单的测试表 CREATE TABLE randy_test (id INT IDENTITY(1,1), num INT) 二:如果强行插入数据时: INSERT INTO randy_test VALUES (1,11) 消息 8101,级别 16,状态 1,

在SQLServer中使用SQL语句插入数据出现乱码或问号的解决方法

错误产生的原因: 出现使用SQL语句插入数据出现乱码或问号是由于数据库属性的排序规则设置不正确. 解决方法: 方法一:手动修改(设置数据库的排序规则) 注意事项:要确定修改的数据库没有被使用,否则会失败! 具体步骤:选中要修改的数据库-->右键-->属性-->弹出数据库属性对话框-->选项-->把排序规则设置成: Chinese_PRC_90_CI_AS-->确定. 方法二:使用代码修改 注意事项:要确定修改的数据库没有被使用,否则会失败!(将数据库连接断开执行这个脚本

SQL Server插入数据的几种方法(基础)

1 insert into table(field1,field2,...) values (value1,value2,...) --插入单条数据 2 3 insert into table(field1,field2,...) select value1,value2,... union select value1,value2,... --插入多条数据,不允许使用default 4 5 insert into table2(field1,field2,...) select field1,