近来有一个项目Feature需要有批量写入数据的场景,正巧整理资料发现自己以前也类似实现的项目,在重构的同时把相关资料做了一个简单的梳理,方便大家参考。

  1. 循环写入(简单粗暴,毕业设计就这样干的)(不推荐)
  2. Bulk Copy写入(>1000K 记录一次性写入推荐)
  3. 表值参数方式写入(mssql 2008新特性)(强烈推荐)

在SQL Server 2008未提供表值参数之前,需要将多行数据传递到存储过程或参数化sql命令我们一般会采用以下几个方法:

  1. 使用一系列单参数来表示多个数据列和行中的值。但使用这个方法会受所允许参数数量限制。Sql server 程序最多可以有2100个参数。服务器必须将这些参数进行再组织成临时表或表变量再进行后续处理。
  2. 将多个数据增加分隔字符串或序列化为xml字符串,然后将这些字符回传服务器。服务器根据解析字符串与xml进行处理。
  3. 将多条写入语句包装在一个单条语句当中。这种方式同sqldataadapter当中的update方法的实现逻辑,可以标识批次处理的个数。不过就算按照包装多个语句进行批次提交,每个语句仍然会分别在服务器上执行。(只是节约了请求的次数而已)
  4. 使用BCP实用工具或SqlBulkCopy对象将很多行数据加载到表中。尽管这荐技术非常有效,但不支持服务器处理,除非将数据加载到临时表或表变量中。

方案一

作为早期学习时出镜率最高的的实现方法我在这里就不特别说明了,在这里直接上码及测试数据:

public static void NormalInsertDate(DataTable dt)
{
using (var sqlConn = new SqlConnection(_testDataConnectionString))
{
var sql = "INSERT INTO Student(Name,Age) VALUES(@Name,@Age)";
using (var cmd = new SqlCommand(sql, sqlConn))
{
sqlConn.Open();
cmd.Parameters.Add("@Name", SqlDbType.NVarChar, );
cmd.Parameters.Add("@Age", SqlDbType.Int);
for (int i = ; i < dt.Rows.Count; i++)
{
cmd.Parameters["@Name"].Value = dt.Rows[i]["Name"];
cmd.Parameters["@Age"].Value = dt.Rows[i]["Age"];
cmd.ExecuteNonQuery();
} }
}
}

  

图一为每次10k条,写10次共计100k条数据总计15329ms

图二为每次100k条,写10次共计1000k条数据总计184395ms

方案二

作为早期批量写入的救星,批量写入的出镜指数4颗星。以下为测试数据:

        public static void BulkInsertData(DataTable dt)
{
using (var sqlConn = new SqlConnection(_testDataConnectionString))
{
using (var bulkCopy = new SqlBulkCopy(sqlConn)
{
DestinationTableName = "Student",
BatchSize = dt.Rows.Count
})
{
sqlConn.Open();
bulkCopy.WriteToServer(dt);
}
}
}

   

图一为每次10k条,写10次共计100k条数据总计1848ms

图二为每次100k条,写10次共计1000k条数据总计21584ms

方案三表值参数方式写入

表值参数提供一种将客户端应用程序中的多行数据封送到 SQL Server 的简单方式,而不需要多次往返或特殊服务器端逻辑来处理数据。您可以使用表值参数来包装客户端应用程序中的数据行,并使用单个参数化命令将数据发送到服务器。传入的数据行存储在一个表变量中,然后您可以通过使用 Transact-SQL 对该表变量进行操作。

可以使用标准的 Transact-SQL SELECT 语句来访问表值参数中的列值。表值参数为强类型,其结构会自动进行验证。表值参数的大小仅受服务器内存的限制。

注意:表值参数只能是输入参数,不能作为输出参数。

以下为相关实现:

1.创建表值参数类型(UDT)

USE Test
--CREATE TABLE
CREATE TABLE Student
(
Id INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(50),
Age INT
)
--create table parameter type
CREATE TYPE StudentUDT AS TABLE
(
Name NVARCHAR(50),
Age INT
)
public static void TableParameterInsertData(DataTable dt)
{
using (var sqlConn = new SqlConnection(_testDataConnectionString))
{
var sql = "INSERT INTO Student(Name,Age) SELECT Name, Age FROM @StudentTVPS";//在这里直接访问表值参数
using (var cmd = new SqlCommand(sql, sqlConn))
{
var catParam = cmd.Parameters.AddWithValue("@StudentTVPS", dt);
catParam.SqlDbType = SqlDbType.Structured;
catParam.TypeName = "StudentUDT";//我们自定义的表值参数类型名称
sqlConn.Open();
cmd.ExecuteNonQuery();
}
}
}

  

图一为每次10k条,写10次共计100k条数据总计390ms

图二为每次100k条,写10次共计1000k条数据总计4451ms

最后我们再横向比较一下:

就我本机测试的情况来看,normal=9*bulk=42*tvps

另外我就一次性大量数据写入对bulk和tvps单独进行了测试,一次性写入100K条数据两种方案基本持平490ms

       

但在一次性写入1000K条数据时差距又再次被拉开,bulk=1.5tvps

就测试数据表明bulk在一次性大量写入依然有不小的优势,毕竟ms就是专门让他来做这个事情的。

然而也可以通过tvps进行分范围写入的方式,总消耗时间有小幅度改善。

所有呢,有大量数据一次性写入场景直接使用bulk copy方式吧。他当仁不让可以高效完成使命。

如果就一些普通业务批量场景无需考虑直接上TVPS方式。他的效率相对于较之前xml参数,复杂参数实现批量写入已经是数量级的提升。

你绝对值得拥有。

由于客户端硬件环境原因,测试环境应该不能非常精确。所以以上数据仅供参考。

欢迎大家一起分享交流。

附件本机测试硬件环境:i7 4770+128 ssd+8G内存;

MSSQL批量写入数据方案的更多相关文章

  1. 使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历

    原文:使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历 常常遇到需要向SQL Server插入批量数据,然后在存储过程中对这些数据进行进一步处理的情况.存储过 ...

  2. HBase BulkLoad批量写入数据实战

    1.概述 在进行数据传输中,批量加载数据到HBase集群有多种方式,比如通过HBase API进行批量写入数据.使用Sqoop工具批量导数到HBase集群.使用MapReduce批量导入等.这些方式, ...

  3. 使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历

    使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历   原文:使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历 常常遇 ...

  4. SQL Server 批量插入数据方案 SqlBulkCopy 的简单封装,让批量插入更方便

    一.Sql Server插入方案介绍 关于 SqlServer 批量插入的方式,有三种比较常用的插入方式,Insert.BatchInsert.SqlBulkCopy,下面我们对比以下三种方案的速度 ...

  5. java连接mysql批量写入数据

    1.采用公认的MYSQL最快批量提交办法 public void index() throws UnsupportedEncodingException, Exception { //1000个一提交 ...

  6. Elasticsearch 5.4.3实战--Java API调用:批量写入数据

    这个其实比较简单,直接上代码. 注意部分逻辑可以换成你自己的逻辑 package com.cs99lzzs.elasticsearch.service.imp; import java.sql.Tim ...

  7. 使用bulkload向hbase中批量写入数据

    1.数据样式 写入之前,需要整理以下数据的格式,之后将数据保存到hdfs中,本例使用的样式如下(用tab分开): row1 N row2 M row3 B row4 V row5 N row6 M r ...

  8. python elasticsearch 批量写入数据

    from elasticsearch import Elasticsearch from elasticsearch import helpers import pymysql import time ...

  9. Shell脚本:向磁盘中批量写入数据

    一.关于本文 工作要做的监控系统需要监控磁盘空间的使用率并报警.在测试这个功能的时候需要模拟两个场景:一是磁盘空间不断增长超过设定的阈值时,需要触发报警机制:二是磁盘空间降落到低于报警阈值的时候,不再 ...

随机推荐

  1. Spring Boot session与cookie的使用

    Session import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import ...

  2. beta冲刺————第二天(2/5)

    完善具体内容: 前端: (1)添加了更多设置 (2)点击后出现底栏,分别可以进行字体背景设置.收藏.分享等操作,同时可以看出对文章的排版进行了完善 后端: 对阿里云服务器中的环境进行配置,同时熟悉阿里 ...

  3. Alpha冲刺&总结报告(12/12)(麻瓜制造者)

    各个成员今日完成的任务 邓弘立: 完成了上传头像的功能 符天愉: 对所有接口进行了再次测试 江郑: 完成了发布需求接口部分的进一步测试和接口文档的编写 刘双玉: 完成了商品信息接口部分的进一步测试和接 ...

  4. 团队作业——Alpha冲刺 10/12

    团队作业--Alpha冲刺 冲刺任务安排 杨光海天 今日任务:编辑界面返回以及预览的intent实现 明日任务:未能按时间要求完成的失败总结 郭剑南 今日任务:优化图像预处理所有功能的函数代码,尝试与 ...

  5. [游记] Noip 2018

    飞雪连天射白鹿, 笑书神侠倚碧鸳 $ 2018/12/14 $ 经历了 \(noip\) 玩完的心态爆炸之后,还是决定稍微写一下游记记录一下\(QAQ\),以免以后就忘了. 然后打算先写个框架之后再慢 ...

  6. 修改Centos7的网卡ens32 改为eth0

    1. 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-eno16777984 修改下面两个配置项 NAME=ens32 DEVICE=ens32 改 ...

  7. Python高级知识点总结

    一.可迭代对象.迭代器对象和生成器 像list, tuple等这些序列是可以使用for...in ...语句来进行遍历输出的.这是为什么呢?这就需要知道可迭代对象(Iterable).迭代器对象(It ...

  8. Ubuntu18.04安装Teamviewer

    首先,打开TeamViewer的下载页面,下载Debian/Ubuntu的Deb安装包. 这里有64位和32位安装包选项.可以在Terminal(终端)中输入uname -a 查看自己系统版本是64位 ...

  9. .NET Core installation for Docker

  10. Java基础—常用类之String类

    一.String类是什么 public final class String implements java.io.Serializable, Comparable<String>, Ch ...