批量更新 SQL 服务器的 C# 代码
Posted
技术标签:
【中文标题】批量更新 SQL 服务器的 C# 代码【英文标题】:C# code to bulk update SQL server 【发布时间】:2013-03-11 04:58:27 【问题描述】:我们有这个 C# 代码,它将根据结构中的标志更新 SQL 服务器数据库表。
public struct stSRK
public string Sno;
public string SClaimID;
public bool SType;
public string SText;
结构中的数据一次最多可以包含 5000-10000 条记录。目前我们正在使用以下 C# 代码来更新数据库,它会根据结构进行“n”次数据库调用。将有助于有一种替代方法来使用相同的 struct 进行批量更新。请看下面的方法
public int UpdateClaims(List<stSRK> _lt, string strClaimType)
try
int iCount = 0;
for (int i = 0; i < _lt.Count; i++)
if (_lt[i].sType == true)
if (_lt[i].SText == 'A')
iCount += Convert.ToInt16(SQL.ExecuteSQL("UPDATE table SET ClaimType = '" + strClaimType + "' WHERE
(Sno = '" + _lt[i].Sno + "' AND ClaimID = '" + _lt[i].SClaimID + "')"));
else
iCount += Convert.ToInt16(SQL.ExecuteSQL("UPDATE table SET ClaimType = '" + strClaimType + "' WHERE
(Sno = '" + _lt[i].Sno + "' AND ClaimID = '" + _lt[i].SClaimID + "')"));
else
if (_lt[i].SText == 'B')
iCount += Convert.ToInt16(SQL.ExecuteSQL("UPDATE table SET ClaimType = '" + strClaimType + "' WHERE
(Sno = '" + _lt[i].Sno + "' AND ClaimID = '" + _lt[i].SClaimID + "')"));
else
iCount += Convert.ToInt16(SQL.ExecuteSQL("UPDATE table SET ClaimType = '" + strClaimType + "' WHERE
(Sno = '" + _lt[i].Sno + "' AND ClaimID = '" + _lt[i].SClaimID + "')"));
return iCount;
catch (Exception e)
throw e.Message;
【问题讨论】:
【参考方案1】:您的查询似乎在所有情况下都是相同的..
你不能重写你的代码来只构建一个 SQL 语句吗?
类似这样的:
public int UpdateClaims(List<stSRK> _lt, string strClaimType)
try
string allSno = String.Join(",", _lt.Select(l=> l.Sno.ToString()).ToArray());
string allClaimID = String.Join(",", _lt.Select(l=> l.SClaimID.ToString()).ToArray());
// Warning: NOT Production code, SQLInjection hazard!
return Convert.ToInt16(SQL.ExecuteSQL("UPDATE table SET ClaimType = '" + strClaimType + @"' WHERE
(Sno IN(" + allSno + ") AND ClaimID IN(" + allClaimID + "))"));
catch (Exception e)
//This is not a good idea, as this way you loose all innerException
// information about the exception. And you might just want to remove
// the try-catch alltogether if you just rethrow the exception.
throw e.Message;
【讨论】:
值得注意的是:这种方法不能很好地扩展到更大的更新 - 理想情况下应该是一种混合方法,您可以批量处理 1,000 条记录(或任何对您正在处理的记录/环境类型有意义的方法和)。如果您使用 200,000 条记录尝试上述方法,SQL Server 可能会在查询解析时严重窒息。 另外,你提出的where子句可能存在逻辑缺陷:如果我想删除Sno=1 AND ClaimID=2
的记录,我想删除Sno=2 AND ClaimID=1
的另一记录,我也会不小心正在删除 Sno=1 AND ClaimID=1
或 Sno=2 AND ClaimID=2
的记录。
谢谢陶,你说的很对,我应该在回答中提到这一点。我跳到了一个可能是错误的假设,即它们总是独一无二的。由 OP 将其置于上下文中,因为我不知道 Sno 是什么意思。
上面写满了 SQL 注入。虽然它只是对 OP 代码的重构,但我真的建议您自己的答案参数化查询。答案有一种被别人当作福音的方式。【参考方案2】:
我的代码:
DataTable tblDetails = new DataTable("tblPlanDetail");
tblDetails.Columns.Add("row1").DataType = typeof(Int32);
tblDetails.Columns.Add("row2").DataType = typeof(DateTime);
tblDetails.Columns.Add("row3").DataType = typeof(String); ;
tblDetails.Columns.Add("row4").DataType = typeof(Int32); ;
for (int i = 0; i < table.Rows.Count; i++)
for (int j = 1; j <= DateTime.DaysInMonth(monthYear.Year, monthYear.Month); j++)
DataRow row = tblDetails.NewRow();
DateTime DayOfMonth = new DateTime(monthYear.Year, monthYear.Month, j);
row["row1"] = idPlan;
row["row2"] = DayOfMonth;
row["row3"] = table.Rows[i][0];
row["row4"] = Int32.Parse((string)table.Rows[i][j]);
tblDetails.Rows.Add(row);
try
SqlBulkCopy sqlbulk = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction);
sqlbulk.ColumnMappings.Add("row1", "row1");
sqlbulk.ColumnMappings.Add("row2", "row2");
sqlbulk.ColumnMappings.Add("row3", "row3");
sqlbulk.ColumnMappings.Add("row4", "row4");
sqlbulk.DestinationTableName = "tblPlanDescription";
sqlbulk.BatchSize = 2;
sqlbulk.WriteToServer(tblDetails);
transaction.Commit();
catch (Exception exp)
transaction.Rollback();
finally
transaction.Dispose();
connection.Close();
即批量插入。 您可以将其插入临时表。 然后你可以执行SP,它会在服务器端创建必要的索引并更新必要的数据
看here
【讨论】:
【参考方案3】:尝试使用 linq 查询进行批量更新。这将提高应用程序的性能。
您可以在此处获得有关大规模更新 linq 查询的帮助:
How to run a mass update/delete query in Linq?
http://msdn.microsoft.com/en-us/library/bb399339.aspx
希望这会对你有所帮助。
【讨论】:
不!对于批量操作,Linq 比 ADO.Net 慢(有时非常慢)。 @EricJ。是吗?我认为linq更快。我还使用 Linq 进行 25000 到 30000 条记录的插入、更新删除。我观察到,它使每秒 20 条记录的操作比 ADO.NET 更快 @Freelancer 是的,对 SQL 数据的批量操作可以比同等的 Linq 快得多。 Linq 插入/更新是逐条记录的,批量操作可以在一次操作中插入/更新数千条记录。 @Freelancer:您是指 Linq-to-SQL 还是 Linq-to-Entities (EF)?我没有使用过 Linq-to-SQL,但在我的用例中,Linq-to-Entities 的速度较慢。谷歌实体框架慢,你会看到很多关于这个问题的帖子。 @EricJ.: EF 在几乎所有种情况下都比较慢以上是关于批量更新 SQL 服务器的 C# 代码的主要内容,如果未能解决你的问题,请参考以下文章