MSSQL批量写入数据方案

近来有一个项目Feature须要有批量写入数据的场景,正巧整理资料发现本身之前也相似实现的项目,在重构的同时把相关资料作了一个简单的梳理,方便你们参考。sql

  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对象将不少行数据加载到表中。尽管这荐技术很是有效,但不支持服务器处理,除非将数据加载到临时表或表变量中。

方案一app

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

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, 50);
                    cmd.Parameters.Add("@Age", SqlDbType.Int);
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        cmd.Parameters["@Name"].Value = dt.Rows[i]["Name"];
                        cmd.Parameters["@Age"].Value = dt.Rows[i]["Age"];
                        cmd.ExecuteNonQuery();
                    }

                }
            }
        }
View Code

   

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

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

方案二测试

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

        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);
                }
            }
        }
View Code

   

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

图二为每次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
)
View Code
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();
        }
    }
}
View Code

   

图一为每次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内存;

相关文章
相关标签/搜索