【发布时间】:2017-05-03 08:24:26
【问题描述】:
我正在使用 EF6 Database.ExecuteSqlCommand 在数据库中执行一些原始 SQL 更新,这似乎是一个非常简单直接的任务。但是,有些更新语句不会随机执行的情况已经发生过几次。该应用程序每天都在积极使用,一天可以插入/更新超过 10,000 行,但有两次 ONE 更新似乎没有运行,一次有大约 20 次更新似乎没有运行。
考虑以下用例:
一个名为Trip的模型,同组中的每个Trip都需要有上一个Trip和下一个Trip的外键。
大约有 5000 次行程需要插入到数据库中。为了导入这些旅行,我需要尽快插入它们,所以我使用 SqlBulkCopy 来完成任务。结果,我无法在插入期间填充外键,因此我必须在之后更新每一行。为此,我在批量复制完成后从数据库中加载所有行程,然后循环遍历它们并执行更新以设置外键。
代码如下所示:
// ... after SqlBulkCopy is done
string tripGroup = null;
Trip previousTrip = null;
foreach (Trip trip in trips)
{
if (tripGroup != trip.TripGroup)
{
tripGroup = trip.TripGroup;
previousTrip = null;
}
if (previousTrip != null)
{
uow.Context.Database.ExecuteSqlCommand("UPDATE [Trips] SET PrevTripId = {0} WHERE Id = {1}", previousTrip.Id, trip.Id);
uow.Context.Database.ExecuteSqlCommand("UPDATE [Trips] SET NextTripId = {0} WHERE Id = {1}", trip.Id, previousTrip.Id);
}
previousTrip = trip;
}
表格如下所示:
问题是有时不会填充 PrevTripId 和 NextTripId。这仅发生在服务器上,我无法在本地开发机器上重现此问题。值得指出的是,在生产中应用服务器和 sql 服务器是分开的。我尝试将代码循环运行 50 次,同时不断进行数据库备份、运行选择等,但我没有运气。
我现在唯一能想到的就是监控结果并做一些记录,这样我就可以知道它什么时候会发生。但我必须等到它再次发生。
非常感谢任何可能导致问题的想法或有关如何重新创建/调试此问题的任何建议。
【问题讨论】:
-
如果要对数据库执行 SQL 命令,为什么要使用 ORM?事实上,您不应该使用 ORM 来执行批量更新。单个
UPDATE语句将执行与 2*N 单独更新相同的工作,速度约为 2*N 倍 -
如何确定 PrevTripID、NextTripId 的值?您可以使用
LAG、LEADT-SQL 函数来访问旅程中的下一个/上一个行程/航段。例如LAG(Id,1,NULL) OVER (PARTITION BY TripGroup ORDER BY ...) as PrevTripId, LEAD(Id,1,NULL, OVER (PARTITION BY TripGroup ORDER BY ...) as NextTripId -
好吧,首先,考虑一下@PanagiotisKanavos 所说的话,100% 同意,然后假设您有充分的理由使用 ORM,看起来您必须实现一些日志记录才能了解发生了什么,我可以想到几件事,但引发警报的是通过 DbContext 和 SQL 混合更新,您可能会遇到“丢失更新”的情况(第一个覆盖后者,所以它似乎没有发生)。还要记住,这两个 SQL 更新是两个独立的事务,在我看来它们应该只是一个。
标签: .net sql-server entity-framework-6