Sql Server海量数据插入

目录

1.前言

2.BULK INSERT

3.简单示例

前言

  由于昨天接到一个客户反馈导出数据卡死的问题,于是决定今天模拟一下千万级的数据,然后傻傻的等待插入数据了半天......

  对于海量数据,上百万上千万的数据插入,我们用ADO.NET提供的普通一条一条数据插入非常非常慢,好在Sql Server为我们提供了批量插入方法。

BULK INSERT

  语法

  

  主要参数说明

  database_name

  指定的表或视图所在的数据库的名称,如果未指定,则默认为当前数据库。

  schema_name

  表或视图架构的名称。

  table_name

  要将数据大容量导入其中的表或视图的名称。

  ‘data_file’

  数据文件的完整路径,该数据文件包含到导入到指定表或视图中的数据。使用BULK INSERT可以从磁盘导入数据。

  BATCHSIZE=batch_size

  指定批量处理中的行数。每个批处理作为一个事物复制到服务器。

  CHECK_CONSTRAINTS
      指定在大容量导入操作期间,必须检查所有对目标表或视图的约束。

  FIELDTERMINATOR =‘field_terminator‘
  指定要用于 char 和 widechar 数据文件的字段终止符,即字段的分隔符。 默认的字段终止符是 \t(制表符)。

  ROWTERMINATOR =‘row_terminator‘
  指定要用于 char 和 widechar 数据文件的行终止符,即行的分隔符。

  

  更多参数说明,请参考: https://msdn.microsoft.com/zh-cn/library/ms188365.aspx

简单示例

  为了对比BULK INSERT和普通逐条插入的差异,我们通过一个简单的示例,通过实际运行来查看效果。  

  第一步:在数据库新建两张一样的表,分表为Student和Student1,表结构完全相同,只有ID,NAME,AGE三个简单的字段。

  

  第二步:新建一个控制台程序,通过一个简单的循环,生成500000条数据写入到txt文件中,关键代码如下:  

 /// <summary>
        /// 生成测试数据
        /// </summary>
        private static void GenerateTestData()
        {
            string fileName = "sql";

            int i = 1;
            while (i <= 500000)
            {
                string strInsert = string.Format("{0},‘test{0}‘,{0}|", i);
                File.AppendText(strInsert, fileName);
                i++;
            }
        }

  第三步:封装出两个方法,分别用来执行批量插入和普通插入,具体代码如下:

/// <summary>
        /// 批量插入测试
        /// </summary>
        private static void BulkInsertTest()
        {
            string strFilePath = @"D:\学习\ASP.NET\QYH.BlukInsertTest\sql.txt";
            string strTableName = "Student";

            /* 每一个字段的信息以“,”分割
            *每一条数据以“|”符号分隔
            * 每10万条数据一个事务*/
            string sql = string.Format("BULK INSERT {0} FROM ‘{1}‘ WITH (FIELDTERMINATOR = ‘,‘,ROWTERMINATOR =‘|‘,BATCHSIZE = 50000)", strTableName, strFilePath);
            DBHelper dbHelper = new DBHelper();
            dbHelper.Excute(sql);

        }

        /// <summary>
        /// 普通插入测试
        /// </summary>
        private static void CommonInsertTest()
        {
            int i = 1;
            while (i <= 500000)
            {
                string sqlInsert = string.Format("insert into Student1(id,Name,Age) values({0},‘test{0}‘,{0})", i);
                new DBHelper().Excute(sqlInsert);
                i++;
            }
        }

  第四步:Main主函数中调用批量插入和普通插入方法,并通过Stopwatch计算出执行时间,Pragram完整代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using QYH.BlukInsertTest.FileMange;
using QYH.BlukInsertTest.DataBase;
using System.Diagnostics;

namespace QYH.BlukInsertTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //用于生成海量数据
            //GenerateTestData();

            Stopwatch stopwatch = Stopwatch.StartNew();
            try
            {
                BulkInsertTest();
            }
            catch (Exception)
            {

                //throw;
            }

            stopwatch.Stop();
            string strResult = "批量插入耗时:" + stopwatch.ElapsedMilliseconds.ToString();

            Stopwatch stopwatch1 = Stopwatch.StartNew();
            CommonInsertTest();
            stopwatch1.Stop();
            string str1Result = "普通插入耗时:" + stopwatch1.ElapsedMilliseconds.ToString();

            string strTestResult = "result";
            File.WriteTextAsync(strResult + "\r\n" + str1Result, strTestResult);

            //Console.Read();
        }

        /// <summary>
        /// 批量插入测试
        /// </summary>
        private static void BulkInsertTest()
        {
            string strFilePath = @"D:\学习\ASP.NET\QYH.BlukInsertTest\sql.txt";
            string strTableName = "Student";

            /* 每一个字段的信息以“,”分割
            *每一条数据以“|”符号分隔
            * 每10万条数据一个事务*/
            string sql = string.Format("BULK INSERT {0} FROM ‘{1}‘ WITH (FIELDTERMINATOR = ‘,‘,ROWTERMINATOR =‘|‘,BATCHSIZE = 50000)", strTableName, strFilePath);
            DBHelper dbHelper = new DBHelper();
            dbHelper.Excute(sql);

        }

        /// <summary>
        /// 普通插入测试
        /// </summary>
        private static void CommonInsertTest()
        {
            int i = 1;
            while (i <= 500000)
            {
                string sqlInsert = string.Format("insert into Student1(id,Name,Age) values({0},‘test{0}‘,{0})", i);
                new DBHelper().Excute(sqlInsert);
                i++;
            }
        }

        /// <summary>
        /// 生成测试数据
        /// </summary>
        private static void GenerateTestData()
        {
            string fileName = "sql";

            int i = 1;
            while (i <= 500000)
            {
                string strInsert = string.Format("{0},‘test{0}‘,{0}|", i);
                File.AppendText(strInsert, fileName);
                i++;
            }
        }
    }
}

  示例中还用到两个辅助类,DBHelper.cs和File.cs,由于仅用于演示,所以写的非常简单,其中文件路径是写死的,可以替换成实际路径。

  DBHelper.cs  

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QYH.BlukInsertTest.DataBase
{
    public class DBHelper
    {
        public string connectionString = "Server=.;Database=QYHDB;User ID=sa;Password=123456;Trusted_Connection=False;";

        public void Excute(string sql)
        {
            SqlConnection conn = new SqlConnection(connectionString);
            SqlCommand command = new SqlCommand();
            command.CommandTimeout = 0;
            command.Connection = conn;
            command.CommandText = sql;
            conn.Open();
            command.ExecuteNonQuery();
            conn.Close();
        }
    }
}

   File.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QYH.BlukInsertTest.FileMange
{
    public class File
    {
        public static string strFilePath = @"D:\学习\ASP.NET\QYH.BlukInsertTest";

        public static async void WriteTextAsync(string text, string fileName)
        {
            using (StreamWriter outputFile = new StreamWriter(strFilePath + @"\" + fileName + ".txt"))
            {
                await outputFile.WriteAsync(text);
            }
        }

        public static void AppendText(string text, string fileName)
        {
            // Append text to an existing file named "WriteLines.txt".
            using (StreamWriter outputFile = new StreamWriter(strFilePath + @"\" + fileName + ".txt",true))
            {
                outputFile.WriteLine(text);
            }
        }
    }
}

  

  一切准备就绪,开始运行,结果如下:

  

  其中单位为毫秒,从结果我们可以看出BULK INSER插入500000条数据还不需要3秒,而普通逐条插入却需要20多分钟

时间: 2024-08-24 06:05:28

Sql Server海量数据插入的相关文章

SQL Server 批量插入数据的两种方法(转)

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

SQL Server 2008 插入修改图片信息

在SQL Server 2008中我们可以用varbinary(max) 数据类型来保存一张图片,不过它的播入与修改与别的数据还是有一点点不同的. 下面看例子: 1.定义表:create table T_Image(ID int not null, BmpImage varbinary(max) not null) 2.向表中插入数据: insert into T_Image(ID,BmpImage) select 1,bulkcolumn --bulkcolumn这个关键字要记下来  大数据列

SQL Server 批量插入数据的两种方法

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

ASP.NET MVC与Sql Server交互, 插入数据

在"ASP.NET MVC与Sql Server建立连接"中,与Sql Server建立了连接.本篇实践向Sql Server中插入数据. 在数据库帮助类中增加插入数据的方法. public class SqlDB { protected SqlConnection conn; //打开连接 public bool OpenConnection() { conn = new SqlConnection(ConfigurationManager.ConnectionStrings[&qu

SQL Server返回插入数据的ID和受影响的行数

首先看看数据库里面的数据(S_Id为自增长标识列): sql server 中返回上一次插入数据的ID(标识值)有三种方式: 第一种 @@IDENTITY: 1 insert into Student(S_StuNo,S_Name,S_Sex,S_Height) 2 values('013','卫庄','男','185'); 3 4 select @@IDENTITY -- 返回 17 @@IDENTITY可以返回当前连接所有范围内插入最后所生成的标识值(包括任何调用的存储过程和触发器).这个函

如何向SQL SERVER 2008 插入图片数据

最近在弄数据库,涉及到插入图片,但2008里已经不在支持TEXTCOPY, 需要用到openrowset.实际上个人认为这个更好用.以下从别处copy的例子 UPDATE and OPENROWSET can be used together to import an image into a table. OPENROWSET can be used to import a file into a single row, single column value. OPENROWSET ( BU

SQL Server 海量数据查询代码优化以及建议

1.应尽量避免在  where  子句中对字段进行   null  值推断,否则将导致引擎放弃使用索引而进 行全表扫描,如: select id from t where num is null 能够在num 上设置默认值0 ,确保表中num 列没有null 值,然后这样查询: select id from t where num=0 2.应尽量避免在  where  子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫 描.优化器将无法通过索引来确定将要命中的行数, 因此须要搜索该

sql server返回插入数据表的id,和插入时间

假设要插入数据的数据表结构如下 id为自增列, insert  into UserInfo (username,userpass,email,RegTime)  output inserted.ID values('AAAAA','AAAAA','AAAAA',getdate());insert  into UserInfo (username,userpass,email,RegTime)  output inserted.ID values('AAAAA','AAAAA','AAAAA',C

SQL Server 批量插入数据的方法

运行下面的脚本,建立测试数据库和表. --Create DataBase create database BulkTestDB; go use BulkTestDB; go --Create Table Create table BulkTestTable ( Id int primary key, UserName nvarchar(32), Pwd varchar(16) ) go --Create Table Valued CREATE TYPE BulkUdt AS TABLE ( Id