近来有一个项目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. Linux运维之系统性能---vmstat工具分析内存的瓶颈

    为了提高磁盘存取效率, Linux做了一些精心的设计, 除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换), 还采取了两种主要Cache方式:Buffer Cache和Page ...

  2. 【Alpha】团队项目测试报告与用户反馈

    测试报告 一 . WEB端测试 测试页面 测试功能/界面 功能/界面简述 测试预期效果 测试目的 是否完成(Y/N) Internet Explorer Google chrome Firefox S ...

  3. 第二次项目冲刺(Beta版本)2017/12/8

    一.任务分布 二.燃尽图 三.站立式会议 1.照片(就要传了) 2.任务安排 四.总结 这次吸收了上次的教训,将任务进行更加详细的分布,分工更加明确,果然效率就高多了,哈哈哈.

  4. Django商城项目笔记No.9用户部分-注册接口签发JWTtoken

    Django商城项目笔记No.9用户部分-注册接口签发JWTtoken 我们在验证完用户的身份后(检验用户名和密码),需要向用户签发JWT,在需要用到用户身份信息的时候,还需核验用户的JWT. 关于签 ...

  5. laravel记录笔记Laravel 连接数据库、操作数据库的三种方式

    laravel中提供DB facade(原始查找).查询构造器.Eloquent ORM三种操作数据库方式 1.连接数据库 .env 数据库配置 DB_HOST=localhost dbhost DB ...

  6. yarn的学习-2-从 npm 迁移到 yarn-包管理工具

    从npm处迁移过来多许多用户来说是一个相对简单的过程.yarn能想npm一样定制相同的package.json,并能够从npm仓库下载任意的包 如果你想要在已存在的npm项目中使用yarn,运行yar ...

  7. OpenCV——图像修补

  8. mysql做了主从,删除binlog日志

    在主服务器操作: 1.查看当前主从库是用哪个binlog日志在做组从 show master status show  slave status 2.查看主库的binlog日志 show master ...

  9. javascript实现拖曳与拖放图片

    javascript实现拖曳与拖放图片 其实对于drag和drop拖曳与拖放事件IE很早以前就支持这个操作了,我们先来看看HTML5中新增的拖放API. 在HTML5中想要实现拖放操作,至少要做以下操 ...

  10. HDU1166

    https://vjudge.net/contest/66989#problem/A C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直 ...