如何/什么是批量数据库插入的最佳方式?
在C#中,我正在迭代一个集合并为集合中的每个项目调用插入存储过程。
如何在一次数据库通话中发送所有数据?
E.g。说我有一个包含10个项目的人名单(List<Person>
)。我目前正在调用InsertPerson存储过程10次。我想把这个减少到1个电话。
我正在使用MS SQL Server 2005。
答案 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
是你的朋友。您需要做的只是提供DataTable
或IDataReader
(我首选的选项,'我喜欢流媒体API)。我做了类似here的事情(你可以忽略xml方面 - 只是SimpleDataReader的子类)。
答案 2 :(得分:7)
.NET SqlBulkCopy类运行良好。
答案 3 :(得分:2)
您可以构建BLOB(图像)并将其作为参数发送到存储过程。在存储过程中,您可以使用substring()获取所有项目。
答案 4 :(得分:2)
以下是SqlBulkCopy
实施的一个很好的例子:
http://blogs.msdn.com/nikhilsi/archive/2008/06/11/bulk-insert-into-sql-from-c-app.aspx
答案 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解决方案,我创建了一个类,而不是Datatable
或List<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();