zoukankan      html  css  js  c++  java
  • SqlBulkCopy快速批量大数据插入

    测试数据表
    CREATE TABLE [dbo].[Demo](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [Time] [datetime] NULL,
        [Name] [nvarchar](50) NULL,
        [Has] [bit] NULL,
        [Age] [int] NULL
    ) ON [PRIMARY]
    .Net批量插入
    private void batchInsert()
    {
                DataTable dt = new DataTable("demo");
                dt.Columns.Add("ID", typeof(System.Int32)); //虽然ID为自增字段,但仍然要添加列,否则会报异常“来自数据源的 String 类型的给定值不能转换为指定目标列的类型 datetime。”
                dt.Columns.Add("Time", typeof(System.DateTime));
                dt.Columns.Add("Name", typeof(System.String));
                dt.Columns.Add("Has", typeof(System.Int32));
                dt.Columns.Add("Age", typeof(System.Int32));
    
                for (int i = 0; i < 100000; i++)
                {
                    DataRow dr = dt.NewRow();
                    dr["Time"] = DateTime.Now;
                    dr["Name"] = "Demo";
                    dr["Has"] = 1;
                    dr["Age"] = 10;
                    dt.Rows.Add(dr);
                }
                AddDataTable(dt);
    }
    
    public bool AddDataTable(DataTable dt)
    {
                using (SqlConnection conn = new SqlConnection(sqlHelper.SQLConString))
                {
                    SqlTransaction transaction = null;
                    try
                    {
                        conn.Open();
                        transaction = conn.BeginTransaction();
                        SqlBulkCopy sbc = new SqlBulkCopy(conn, SqlBulkCopyOptions.CheckConstraints, transaction);
                        sbc.DestinationTableName = dt.TableName;
                        sbc.BatchSize = dt.Rows.Count;
                        sbc.BulkCopyTimeout = 180;
                        sbc.WriteToServer(dt);
                        transaction.Commit();
                        return true;
                    }
                    catch (Exception ex)
                    {
                        LogMsg.WriteLog(ex.ToString());
                        transaction.Rollback();
                    }
                }
    
                return false;
    }
    VB.Net批量插入
    Protected SQLConString As String = ConfigurationManager.ConnectionStrings("connectionstring").ToString()
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim startDate As DateTime = DateTime.Now
            'batchInsert()  '1198.6272毫秒
            OneInsert()  '604554.6833毫秒
            Dim endDate As DateTime = DateTime.Now
            Response.Write((endDate - startDate).TotalMilliseconds)
    
    End Sub
    
    '单条数据添加
    Private Sub OneInsert()
            Using conn As New SqlClient.SqlConnection(SQLConString)
                Try
                    conn.Open()
                    Dim cmd As New SqlClient.SqlCommand
                    cmd.Connection = conn
                    cmd.CommandType = CommandType.Text
                    For index = 1 To 100000
                        cmd.CommandText = "insert demo(Time,Name,Has,Age)values('" & DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") & "','第一个',1,18)"
                        cmd.ExecuteNonQuery()
                    Next
                Catch ex As Exception
    
                End Try
            End Using
    End Sub
    
    '一次性批量添加
    Private Sub batchInsert()
            Dim dt As New DataTable("demo")
            dt.Columns.Add("ID", GetType(Integer)) '虽然ID为自增字段,但仍然要添加列,否则会报异常“来自数据源的 String 类型的给定值不能转换为指定目标列的类型 datetime。”
            dt.Columns.Add("Time", GetType(DateTime))
            dt.Columns.Add("Name", GetType(String))
            dt.Columns.Add("Has", GetType(Integer))
            dt.Columns.Add("Age", GetType(Integer))
    
    
            For i = 1 To 100000
                Dim row As DataRow = dt.NewRow()
                row("Time") = DateTime.Now
                row("Name") = "第一个"
                row("Has") = 1
                row("Age") = 18
                dt.Rows.Add(row)
            Next
    
            Using conn As New SqlClient.SqlConnection(SQLConString)
                Dim transaction As SqlClient.SqlTransaction
                Try
                    conn.Open()
                    transaction = conn.BeginTransaction()
                    Dim sbc As New SqlClient.SqlBulkCopy(conn, SqlBulkCopyOptions.CheckConstraints, transaction)
                    sbc.DestinationTableName = dt.TableName
                    sbc.BatchSize = dt.Rows.Count
                    sbc.BulkCopyTimeout = 180
                    sbc.WriteToServer(dt)
                    transaction.Commit()
                Catch ex As Exception
                    transaction.Rollback()
                End Try
            End Using
    End Sub
    效率对比

    通过上面的VB.NET的两种添加方式对比,同样是一次性添加10w数据,以下是他们的执行时间:

    (时间单位:毫秒)

    SqlBulkCopy:1198.6272≈1秒

    for insert:604554.6833≈10分钟

    使用中遇到的小问题(Q&A)

    问题1:从bcp客户端收到一个对Colid 24 无效的列长度

    原因:第24列的参数长度大于数据库列定义长度。

    问题2:报异常“来自数据源的 String 类型的给定值不能转换为指定目标列的类型 datetime。”

    原因: 没有添加自增列。

  • 相关阅读:
    用优先级队列实现先进先出队列;
    c#入门经典(第三版) 练习6.8(5)
    请给出一个时间为O(nlgk)、用来将k个已排序链表的算法。此处n为所有输入链表中元素的总数。
    计数排序
    Heap_delete(A,i)操作将结点i中的想从堆A中删去。对含n个元素的最大堆,请给出时间为O(lgn)的HEAPDELETE的实现。
    堆排序
    请给出一个算法,使之对于给定的介于0到k之间的n个整数进行预处理,并能在O(1)时间内,回答出输入的整数中有多少个落在区间[a..b]内,你给出的算法上预处理时间应是O(n+k)。
    sql存储过程传多个id查询,使用in
    SQL使用语句修改列及表名
    泛型约束使用?有些不知道叫什么好!
  • 原文地址:https://www.cnblogs.com/hougelou/p/2854655.html
Copyright © 2011-2022 走看看