我正在使用EF6 Database.ExecuteSqlCommand在数据库中执行一些原始SQL更新,这似乎是一个非常简单和直接的任务。但是,有几次更新语句不会随机执行。该应用程序每天都在积极使用,一天内可以插入/更新超过10,000行,但有两次ONE更新似乎没有运行,有一次有大约20次更新似乎没有运行。
考虑以下用例:
名为Trip的模型,同一组中的每个Trip都需要拥有前一个Trip和下一个Trip的外键。
需要将大约5000次旅行插入数据库。为了导入这些Trips,我需要尽快插入它们,所以我使用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 server是分开的。我尝试将代码放在循环中运行50次,同时不断进行数据库备份,运行选择等,但我没有运气。
我现在唯一能想到的就是监控结果并做一些日志记录,以便我可以看到它何时会发生。但我必须等到它再次发生。
非常感谢任何可能导致问题的原因或有关如何重新创建/调试此问题的任何建议。
答案 0 :(得分:0)
ORM不适合批处理操作,无论这些操作涉及批量加载还是批量更新。此代码绕过ORM本身每行发送2个UPDATE语句,导致2N操作 plus 加载内存中的所有数据。
使用SQL执行批处理操作要简单得多,速度更快,更安全。一些SQL语句可以更新单个事务中的所有行,而无需在客户端上加载任何内容。
在这种情况下,您可以利用LAG和LEAD分析函数来检索分区中的上一个/下一个值。
假设旅行按ID排序并由TripGroup分区,您可以使用以下方式检索上一个/下一个ID:
select
id,
LAG(ID,1,null) OVER (Partition by TripGroup order by id) as PrevTripID,
LEAD(ID,1,null) OVER (Partition by TripGroup order by id) as NextTripId
from Trips;
这将返回与图片中发布的结果相同的结果。
要更新Trips,您需要使用CTE,因为分析函数只能在SELECT语句中使用:
with ids as (
select
id,
LAG(ID,1,null) OVER (Partition by TripGroup order by id) as PrevTripID,
LEAD(ID,1,null) OVER (Partition by TripGroup order by id) as NextTripId
from Trips
)
update t
set
PevTripId =ids.PrevTripID,
NextTripId =ids.NextTripId
from Trips t inner join ids on ids.Id=t.id;
您只需要一个语句,而不是加载5000行并执行10000个命令。