从c#批量数据库插入的最佳方法是什么?

时间:2009-03-25 15:04:45

标签: c# sql-server

如何/什么是批量数据库插入的最佳方式?

在C#中,我正在迭代一个集合并为集合中的每个项目调用插入存储过程。

如何在一次数据库通话中发送所有数据?

E.g。说我有一个包含10个项目的人名单(List<Person>)。我目前正在调用InsertPerson存储过程10次。我想把这个减少到1个电话。

我正在使用MS SQL Server 2005。

10 个答案:

答案 0 :(得分:27)

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

答案 1 :(得分:25)

好吧,10个项目不是我称之为批量的,但对于较大的集合,SqlBulkCopy是你的朋友。您需要做的只是提供DataTableIDataReader(我首选的选项,'我喜欢流媒体API)。我做了类似here的事情(你可以忽略xml方面 - 只是SimpleDataReader的子类)。

答案 2 :(得分:7)

.NET SqlBulkCopy类运行良好。

答案 3 :(得分:2)

您可以构建BLOB(图像)并将其作为参数发送到存储过程。在存储过程中,您可以使用substring()获取所有项目。

答案 4 :(得分:2)

答案 5 :(得分:2)

我将列表构造为xml字符串并将其传递给存储过程。在SQL 2005中,它增强了xml功能以解析xml并进行批量插入。

查看这篇文章: Passing lists to SQL Server 2005 with XML Parameters

答案 6 :(得分:1)

将数据转储到以分隔的管道(或其他内容,如果您的数据中有管道)文本文件并使用Bulk Insert

答案 7 :(得分:1)

您可以使用Xml文档进行更新,Sql 2005可以很好地与它们配合使用。每行一个节点,但只有一个Xml参数。

答案 8 :(得分:1)

创建一个包含要插入的所有项目的XML文档。然后在存储过程内部,使用TSQL xml支持(OPENXML)从XML文档中读取所有数据并将其插入到表中,希望每个表都有一个insert语句。

但是,如果您只是将数据插入到单个表中而不需要任何数据库端逻辑,为什么不使用SqlBulkCopy

答案 9 :(得分:1)

为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();