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

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

  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万条数据,代码如下:

  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中的数据插入到数据库

代码如下:

  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,我也会另外写一篇关于表值参数的博客,不过此次不对表值参数的概念做过多的介绍。言归正传,看代码:

  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秒。

SQL一次性插入大量数据【转载】的更多相关文章

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

    在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍SQL Server支持的两种批量 ...

  2. SQL循环插入批量数据

    declare @i intdeclare @qid int set @i=1set @qid=100 while @i<50000begininsert into Order(orderid, ...

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

    今天在做项目的过程中遇到如标题的问题,情况如下图: 数据库使用的是SQL Server2012版本,创建表的脚本如下: CREATE TABLE [dbo].[Type](  [TypeId] INT ...

  4. Java 向SQL Server插入文件数据

    package sqlserver; import java.util.Date; import java.util.UUID; import java.text.SimpleDateFormat; ...

  5. SQL Server插入中文数据出现乱码问题

    我在用sql server存储数据的时候发现中文全变成了问号,我知道中文是特殊的编码.所以在数据库设计的时候包含中文的字段就是nvarchar,但是还是成了问号 好了,不多说了,解决方案如下: 在存储 ...

  6. tp5 一次性插入大量数据时分批处理

    如题,加入$arr 中有一万多条数据,如果直接使用insert插入的话就会报错,此时可以使用limit分批插入 $result = Db::connect($this->dbconfig()) ...

  7. ado.net 向sql中插入新数据的同时获取自增重的id值

    两种方法都可以实现: 要获取的自增长列为phonebookID 方法一: sql = "insert into phonebook (mobile,peoplename) output in ...

  8. Java向数据库中一次性插入大量数据

    String sql = “insert into username.tablename(id) values(?)”; PreparedStatement stmt = conn.prepareSt ...

  9. mysql 一次性插入的数据量过大报错max_allowed_packet解决方法

    查询: show VARIABLES like ‘%max_allowed_packet%‘; 记录下数字(默认是一个7位) 执行语句: ; 重启服务 再查询 该数字 ,如果没变,则修改mysql的m ...

随机推荐

  1. C#下的摄像机标定

    前言:计算机视觉的基本任务之一是从摄像机获取的图像信息出发计算三维空间中物体的几何信息,并由此重建和识别物体,而空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系是由摄像机成像的几何模型决 ...

  2. EasyDSS RTMP流媒体解决方案之Windows服务安装方案

    Windows服务安装 EasyDSS_Solution流媒体解决方案,可以通过start一键启动.在实际应用中,我们希望可以设置成系统服务,那么下面我将会介绍,如何在windows中将流媒体解决方案 ...

  3. Eclipse + JDK + tomcat开发环境配置

       第一步:下载jdk和tomcat:JDK下载  Tomcat下载     最新的jdk为1.6.10,tomcat为6.0,建议jdk1.4以上,tomcat4.0以上    第二步:安装和配置 ...

  4. iOS SQLite使用

    数据库的特征: 以一定方式存储在一起 能为多个用户分享 具有尽可能少的冗余代码 与程序彼此独立的数据集 SQLite SQLite是一个轻量级关系数据库,最初的设计目标是用于嵌入式系统,它占用资源非常 ...

  5. Azkaban_Oozie_action

    http://azkaban.github.io/azkaban/docs/2.5/ There is no reason why MySQL was chosen except that it is ...

  6. Python文件编码不可以使用UTF16

    1. The complete Python source file should use a single encoding. Embedding of differently encoded da ...

  7. Django框架ORM单表删除表记录_模型层

    此方法依赖的表是之前创建的过的一张表 参考链接:https://www.cnblogs.com/apollo1616/p/9840354.html 1.删除方法就是delete(),它运行时立即删除对 ...

  8. python 的print 用法

    print(x,y) 等价于 import sys sys.stdout.write(str(x) + ' ' +str(y) + '\n') 从语法上讲,调用python3.0 的print 函数有 ...

  9. Tomcat部署java项目java.lang.OutOfMemoryError异常解决方法

    java.lang.OutOfMemoryError异常解决方法 Window系统环境下,在catalina.bat文件第一行添加以下内容 set JAVA_OPTS=-Xms512m -Xmx512 ...

  10. oracle数据库如何备份一张表

    --用户名:tms--创建表ts_dictionary的备份create table ts_dictionary_20160715 as select * from ts_dictionary; 补充 ...