简体   繁体   English

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

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

How do I/what's the best way to do bulk database inserts? 我如何/什么是批量数据库插入的最佳方式?

In C#, I am iterating over a collection and calling an insert stored procedure for each item in the collection. 在C#中,我正在迭代一个集合并为集合中的每个项调用插入存储过程。

How do I send all the data in one database call? 如何在一次数据库调用中发送所有数据?

Eg say I have a person list ( List<Person> ) containing 10 items. 例如,我说我有一个包含10个项目的人员列表( List<Person> )。 I am currently calling the InsertPerson stored proc 10 times. 我目前正在调用InsertPerson存储过程10次。 I would like to reduce this to 1 call. 我想将此减少到1个电话。

I am using MS SQL Server 2005. 我正在使用MS SQL Server 2005。

CsharperGuyInLondon, here's a simple example of SqlBulkCopy code: 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);
}

Well, 10 items isn't what I call bulk, but for larger sets, SqlBulkCopy is your friend. 好吧,10个项目不是我称之为批量,但对于较大的集合, SqlBulkCopy是你的朋友。 All you need to do is feed it either a DataTable or an IDataReader (my preferred option, 'cos I like streaming APIs). 您需要做的就是将它提供给DataTableIDataReader (我的首选选项,'我喜欢流API)。 I did something similar here (you can ignore the xml side - just subclass the SimpleDataReader). 我在这里做了类似的事情 (你可以忽略xml方面 - 只是SimpleDataReader的子类)。

.NET SqlBulkCopy类运行良好。

You can build a BLOB (image) and send it as a parameter to a stored procedure. 您可以构建BLOB(图像)并将其作为参数发送到存储过程。 Inside the stored procedure, you can fetch all the items using substring(). 在存储过程中,您可以使用substring()获取所有项目。

I construct the list as an xml string and pass it to the stored proc. 我将列表构造为xml字符串并将其传递给存储过程。 In SQL 2005, it has enhanced xml functionalities to parse the xml and do a bulk insert. 在SQL 2005中,它具有增强的xml功能,可以解析xml并执行批量插入。

check this post: Passing lists to SQL Server 2005 with XML Parameters 查看这篇文章: 使用XML参数将列表传递给SQL Server 2005

Re the solution for SqlBulkCopy, I created a class than takes Datatable or a List<T> and a Buffer size ( CommitBatchSize ). 对于SqlBulkCopy的解决方案,我创建了一个比采用DatatableList<T>和缓冲区大小( CommitBatchSize )的类。 It will convert the list to a data table using an extension (in the second class). 它将使用扩展名(在第二个类中)将列表转换为数据表。

It works very fast. 它工作得非常快。 On my PC, I am able to insert more than 10 million complicated records in less than 10 seconds. 在我的电脑上,我可以在不到10秒的时间内插入超过1000万条复杂的记录。

Here is the class: 这是班级:

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

} }

Here is an example when I want to insert a List of my custom object List<PuckDetection> ( ListDetections ): 下面是一个示例,当我想插入自定义对象List<PuckDetection>ListDetections )时:

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

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

You could update with an Xml document, Sql 2005 works very well with them. 您可以使用Xml文档进行更新,Sql 2005可以很好地与它们配合使用。 One node per row, but just one parameter for Xml. 每行一个节点,但只有一个Xml参数。

Create a XML document that contains all the items to be inserted. 创建一个包含要插入的所有项的XML文档。 Then inside of a stored procedure, use the TSQL xml support ( OPENXML ) to read all the data from the XML document and insert it into your tables with hopefully one insert statement for each table. 然后在存储过程内部,使用TSQL xml支持( OPENXML )从XML文档中读取所有数据并将其插入到表中,希望每个表都有一个insert语句。

However if you are only inserting data into a single table and don't need any database side logic, why not use SqlBulkCopy ? 但是,如果您只是将数据插入到单个表中而不需要任何数据库端逻辑,为什么不使用SqlBulkCopy

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在大型 c# 应用程序上进行批量命名空间重命名的最佳方法是什么? - What's the best way to do a bulk namespace rename on a large c# application? 从 C# 连接和使用 sqlite 数据库的最佳方法是什么? - What is the best way to connect and use a sqlite database from C# 从C#DataTable批量插入的最佳方法 - Best way to Bulk Insert from a C# DataTable 在破坏C#中的批量插入之后,数据库日志文件正在增长 - Database Log file growing , after ruining Bulk inserts in C# 在C#中处理批量邮件的最佳方式 - Best Way to handle Bulk Mail in C# 使用C#将Bulk Xml(XElement)数据插入Sql server Table的最佳方法是什么? - What is the best way to insert Bulk Xml (XElement) data to Sql server Table using C#? 在C#中处理多个数据库连接的最佳方法是什么? - What is the best way to handle multiple database connections in C# 我通过 C# 连接到离线数据库的最佳方式是什么 - What is the best way for me to connect to a offline database through C# 在C#中,确定数据库是否已启动并正在运行的最佳方法是什么? - In C# what is the best way to determine if a database is up and running? 在ASP.NET C#中从数据库显示图像的最佳方法是什么 - What is the Best way to show Images from database in asp.net C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM