C# 不带datatable的SqlBulkCopy列表
我们有一个大约100000条记录的大列表,希望将其插入到sql表中 我们正在做的是;将该列表转换为数据表并将数据表传递给SqlBulkcopy方法 从列表到数据表的转换需要更多的时间。尝试使用并行,但由于Datatable不是线程安全的,因此避免了 添加生成整数列表并将其插入临时表的示例poc代码C# 不带datatable的SqlBulkCopy列表,c#,.net,multithreading,sqlbulkcopy,C#,.net,Multithreading,Sqlbulkcopy,我们有一个大约100000条记录的大列表,希望将其插入到sql表中 我们正在做的是;将该列表转换为数据表并将数据表传递给SqlBulkcopy方法 从列表到数据表的转换需要更多的时间。尝试使用并行,但由于Datatable不是线程安全的,因此避免了 添加生成整数列表并将其插入临时表的示例poc代码 static void Main(string[] args) { List<int> valueList = GenerateList(100000);
static void Main(string[] args)
{
List<int> valueList = GenerateList(100000);
Console.WriteLine("Starting with Bulk Insert ");
DateTime startTime = DateTime.Now;
int recordCount = BulkInsert(valueList);
TimeSpan ts = DateTime.Now.Subtract(startTime);
Console.WriteLine("Bulk insert for {0} records in {1} miliseconds.-> ", recordCount, ts.Milliseconds);
Console.WriteLine("Done.");
Console.ReadLine();
}
private static int BulkInsert(List<int> valueList)
{
SqlBulkHelper sqlBulkHelper = new SqlBulkHelper();
var eventIdDataTable = CreateIdentityDataTable(valueList, "SqlTable", "Id");
return FillBulkPoundTable(eventIdDataTable, "#SqlTable");
}
private static List<int> GenerateList(int size)
{
return Enumerable.Range(0, size).ToList();
}
private static DataTable CreateIdentityDataTable(List<int> ids, string dataTableName, string propertyName)
{
if (ids == null) return null;
using (var dataTable = new DataTable(dataTableName))
{
dataTable.Locale = CultureInfo.CurrentCulture;
var dtColumn = new DataColumn(propertyName, Type.GetType("System.Int32"));
dataTable.Columns.Add(dtColumn);
foreach (int id in ids)
{
DataRow row = dataTable.NewRow();
row[propertyName] = id;
dataTable.Rows.Add(row);
}
return dataTable;
}
}
private static int FillBulkPoundTable(DataTable dataTable, string destinationTableName)
{
int totalInsertedRecordCount = 0;
using (SqlConnection _connection = new SqlConnection(CongifUtil.sqlConnString))
{
string sql =
@"If object_Id('tempdb..#EventIds') is not null drop table #EventIds
CREATE TABLE #EventIds(EvId int) ";
_connection.Open();
using (var command = new SqlCommand(sql, _connection))
{
command.ExecuteNonQuery();
}
using (var sqlBulkCopy = new SqlBulkCopy(_connection))
{
sqlBulkCopy.BulkCopyTimeout = 0;
sqlBulkCopy.DestinationTableName = destinationTableName;
sqlBulkCopy.WriteToServer(dataTable);
}
using (var command = new SqlCommand(sql, _connection))
{
command.CommandText = "Select Count(1) as RecordCount from #EventIds";
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
totalInsertedRecordCount = Convert.ToInt32(reader["RecordCount"]);
}
}
}
}
return totalInsertedRecordCount;
}
目前需要8秒左右的时间,但我们需要加快速度。原因是我们的目标是插入900000条记录,每个记录将分为100000批
你能给我们一些提示,我们怎样才能使它更完美、更快
另外,也尝试过使用Dapper insert,但它并不比BulkCopy快。首先将列表转换为XML,例如
List<int> Branches = new List<int>();
Branches.Add(1);
Branches.Add(2);
Branches.Add(3);
XElement xmlElements = new XElement("Branches", Branches.Select(i => new
XElement("branch", i)));
然后将xml作为参数传递给SP,并将其直接插入到表中,例如:
DECLARE @XML XML
SET @XML = '<Branches>
<branch>1</branch>
<branch>2</branch>
<branch>3</branch>
</Branches>'
DECLARE @handle INT
DECLARE @PrepareXmlStatus INT
EXEC @PrepareXmlStatus= sp_xml_preparedocument @handle OUTPUT, @XML
SELECT * FROM OPENXML(@handle, '/Branches/branch', 2)
WITH (
branch varchar
)
EXEC sp_xml_removedocument @handle
巴赫尺寸
据我所知,您尝试以100000的批大小插入。高并不总是好的
尝试将该值降低到5000,并检查性能差异
您增加了数据库往返的数量,但由于此处涉及的行大小等因素太多,也可能会加快速度
台锁
使用SqlBulkCopyOptions.TableLock将提高插入性能
using (var sqlBulkCopy = new SqlBulkCopy(_connection, SqlBulkCopyOptions.KeepIdentity))
因此,在没有看到代码的情况下,您希望我们建议将其完善并更快吗?对于初学者来说,如果你能说明你希望它更加完美,那会有帮助吗?30%还是70%?我们做的不超过90%。还要快多少?10分钟以内行吗?如果您能展示需要完美和快速的代码,我们的任务会更容易一些,但我不妨告诉您,代码审查问题在这里有点离题,可能会在codereview.se上出现。这种形式的这个不会。因此,首先要改进它,然后考虑你的选择。使用一个替代DATATATE会省去开销。同意你的观点雷内。添加了示例代码。具体需要8秒的时间?只有sqlBulkCopy.WriteToServer方法还是整个程序?在我看来,只有10万排的座位有点高。嗨,阿比,试过这一排。从xml插入比从BulkCopy插入慢