• 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 数据文件的字段终止符,即字段的分隔符。 默认的字段终止符是 (制表符)。

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

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

    /// <summary>
            /// 批量插入测试
            /// </summary>
            private static void BulkInsertTest()
            {
                string strFilePath = @"D:学习ASP.NETQYH.BlukInsertTestsql.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++;
                }
            }
    View Code

       第四步: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 + "
    " + str1Result, strTestResult);
    
                //Console.Read();
            }
    
            /// <summary>
            /// 批量插入测试
            /// </summary>
            private static void BulkInsertTest()
            {
                string strFilePath = @"D:学习ASP.NETQYH.BlukInsertTestsql.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++;
                }
            }
        }
    }
    View Code

      示例中还用到两个辅助类,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();
            }
        }
    }
    View Code

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

      

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

      

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

          

  • 相关阅读:
    一个程序员的负罪感
    【软件安装记录篇】本地虚拟机Centos7快速安装MySQL
    三分钟熟悉进制转换与位运算
    Base64 编码原理
    Java 注解
    数据结构之链表-动图演示
    数据结构之红黑树-动图演示(下)
    数据结构之红黑树-动图演示(上)
    通过TreeMap 和 冒泡算法对JSON 进行排序
    Quartz 之 windowService
  • 原文地址:https://www.cnblogs.com/qianxingdewoniu/p/6119791.html
Copyright © 2020-2023  润新知