簡體   English   中英

從c#批量數據庫插入的最佳方法是什么?

[英]What’s the best way to bulk database inserts from c#?

我如何/什么是批量數據庫插入的最佳方式?

在C#中,我正在迭代一個集合並為集合中的每個項調用插入存儲過程。

如何在一次數據庫調用中發送所有數據?

例如,我說我有一個包含10個項目的人員列表( List<Person> )。 我目前正在調用InsertPerson存儲過程10次。 我想將此減少到1個電話。

我正在使用MS SQL Server 2005。

CsharperGuyInLondon,這是SqlBulkCopy代碼的一個簡單示例:

using System.Data.SqlClient;

DataTable table = new DataTable("States");
// construct DataTable
table.Columns.Add(new DataColumn("id_state", typeof(int))); 
table.Columns.Add(new DataColumn("state_name", typeof(string)));

// note: if "id_state" is defined as an identity column in your DB,
// row values for that column will be ignored during the bulk copy
table.Rows.Add("1", "Atlanta");
table.Rows.Add("2", "Chicago");
table.Rows.Add("3", "Springfield");

using(SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString))
{
  bulkCopy.BulkCopyTimeout = 600; // in seconds
  bulkCopy.DestinationTableName = "state";
  bulkCopy.WriteToServer(table);
}

好吧,10個項目不是我稱之為批量,但對於較大的集合, SqlBulkCopy是你的朋友。 您需要做的就是將它提供給DataTableIDataReader (我的首選選項,'我喜歡流API)。 我在這里做了類似的事情 (你可以忽略xml方面 - 只是SimpleDataReader的子類)。

.NET SqlBulkCopy類運行良好。

您可以構建BLOB(圖像)並將其作為參數發送到存儲過程。 在存儲過程中,您可以使用substring()獲取所有項目。

我將列表構造為xml字符串並將其傳遞給存儲過程。 在SQL 2005中,它具有增強的xml功能,可以解析xml並執行批量插入。

查看這篇文章: 使用XML參數將列表傳遞給SQL Server 2005

對於SqlBulkCopy的解決方案,我創建了一個比采用DatatableList<T>和緩沖區大小( CommitBatchSize )的類。 它將使用擴展名(在第二個類中)將列表轉換為數據表。

它工作得非常快。 在我的電腦上,我可以在不到10秒的時間內插入超過1000萬條復雜的記錄。

這是班級:

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

namespace DAL
{

public class BulkUploadToSql<T>
{
    public IList<T> InternalStore { get; set; }
    public string TableName { get; set; }
    public int CommitBatchSize { get; set; }=1000;
    public string ConnectionString { get; set; }

    public void Commit()
    {
        if (InternalStore.Count>0)
        {
            DataTable dt;
            int numberOfPages = (InternalStore.Count / CommitBatchSize)  + (InternalStore.Count % CommitBatchSize == 0 ? 0 : 1);
            for (int pageIndex = 0; pageIndex < numberOfPages; pageIndex++)
                {
                    dt= InternalStore.Skip(pageIndex * CommitBatchSize).Take(CommitBatchSize).ToDataTable();
                BulkInsert(dt);
                }
        } 
    }

    public void BulkInsert(DataTable dt)
    {
        using (SqlConnection connection = new SqlConnection(ConnectionString))
        {
            // make sure to enable triggers
            // more on triggers in next post
            SqlBulkCopy bulkCopy =
                new SqlBulkCopy
                (
                connection,
                SqlBulkCopyOptions.TableLock |
                SqlBulkCopyOptions.FireTriggers |
                SqlBulkCopyOptions.UseInternalTransaction,
                null
                );

            // set the destination table name
            bulkCopy.DestinationTableName = TableName;
            connection.Open();

            // write the data in the "dataTable"
            bulkCopy.WriteToServer(dt);
            connection.Close();
        }
        // reset
        //this.dataTable.Clear();
    }

}

public static class BulkUploadToSqlHelper
{
    public static DataTable ToDataTable<T>(this IEnumerable<T> data)
    {
        PropertyDescriptorCollection properties =
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }
}

}

下面是一個示例,當我想插入自定義對象List<PuckDetection>ListDetections )時:

var objBulk = new BulkUploadToSql<PuckDetection>()
{
        InternalStore = ListDetections,
        TableName= "PuckDetections",
        CommitBatchSize=1000,
        ConnectionString="ENTER YOU CONNECTION STRING"
};
objBulk.Commit();

將數據轉儲到管道分隔(或其他內容,如果您的數據中有管道)文本文件並使用批量插入

您可以使用Xml文檔進行更新,Sql 2005可以很好地與它們配合使用。 每行一個節點,但只有一個Xml參數。

創建一個包含要插入的所有項的XML文檔。 然后在存儲過程內部,使用TSQL xml支持( OPENXML )從XML文檔中讀取所有數據並將其插入到表中,希望每個表都有一個insert語句。

但是,如果您只是將數據插入到單個表中而不需要任何數據庫端邏輯,為什么不使用SqlBulkCopy

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM