【问题标题】:How to get round 'The wait operation timed out'如何解决“等待操作超时”
【发布时间】:2016-06-28 13:32:56
【问题描述】:

我正在使用 c 构建电子商务系统。 10000 件产品,每件有 15 个品种,每件都有一个独特的价格来匹配,所以 c. 150,000 个产品价格。价格每天都在变化,这些以 CSV 格式发送给我们,我们自动导入以重写新价格的整个数据库表,因为每天都有超过 95% 的价格会发生变化。由于数字的原因,我们在每个价格上都有一个标志,表明该价格是否是网站上可见的价格。

在我们导入后,昨天在网站上的价格(因此标记为可见),以及新的但不在网站上的价格在 C# 控制台行程序中使用此 LINQ 命令切换其标志:-

db.Database.ExecuteSqlCommand("UPDATE [MyDatabase].[dbo].[ProductVariationPrice] SET IsVisible = IsVisible ^ 1");

所以标记为 IsVisible 的所有内容现在都不可见,反之亦然。即使是 300,000 行,这也只需要不到一秒的时间,然后我们删除设置为 IsVisible = 1 的行范围。

在此之前,我们使用 BulkInsert 快速插入行,并使用 LINQ 的 RemoveRange 删除要删除的不可见项。

最初这很好,但我现在让电子商务网站上的用户在数据标志切换和旧数据被删除的确切时间得到“等待操作超时”错误。

如何在此期间停止此等待操作超时?有人告诉我我们不能做的事情:-

  • 更新每条记录而不是重写整个表(耗时太长)
  • 在新价格生效期间将所有人锁定在系统之外一段时间。

有人可以建议吗?是不是让数据库连接保持打开更长时间?

提前致谢!

更新 以下是围绕瓶颈的完整代码:-

using (TransactionScope transaction = new TransactionScope())
{
    db.Database.ExecuteSqlCommand("UPDATE [MyDatabase].[dbo].[ProductVariationPrice] SET IsVisible = IsVisible ^ 1");
    transaction.Complete();
}

List<ProductVariationPrice> oldProductPrices = db.ProductVariationPrices.Where(x => !x.IsVisible).ToList();
db.ProductVariationPrices.RemoveRange(oldProductPrices);
db.SaveChanges();

【问题讨论】:

  • 删除需要多长时间?是在交易中吗?如果是这样,交易中还有什么?什么是超时的事情?大概这是在与类似的数据交谈 - 读取查询的隔离级别是什么?写查询的隔离级别是多少?以及事务的隔离级别?
  • 嗨,不确定隔离级别是什么(让我谷歌一下)。您在上面看到的 SQL 开关位于事务内部。删除不是。这可能是问题吗?失败的页面是订单篮页面,大概是因为它正在拉回相同的价格......?删除最多需要一两分钟。
  • 如果您使用的是 LINQ-to-SQL 或实体框架(您提到了 LINQ,但这是不明确的),那么当您调用 SubmitChanges()(或其他任何名称)时,它将自动使用事务) - 所以是的,这绝对是个问题。有什么理由你不能在这里只使用一个DELETE ... WHERE ...
  • 1.如果您的表ProductVariationPrice 有许多(数百万或更多)记录,则任何更新都可能需要一段时间。 2. 此外,如果在列IsVisible 上有很多记录和索引,则更新可能需要一段时间,因为索引也都必须更新。 3. Linq 语句中的删除将始终对每条记录执行一个删除语句,因此如果删除导致大量删除(100,000 次删除将是 100,000 条删除语句,一次执行一个),这是执行删除的低效方式),而是使用 sql 语句,就像您对更新所做的那样。
  • 继续)。使用与之前相同的做法并将其包装在事务中。 lwc.Database.ExecuteSqlCommand("DELETE FROM [MyDatabase].[dbo].[ProductVariationPrice] WHERE IsVisible = 0");

标签: c# database linq bulkinsert connection-timeout


【解决方案1】:

改变你的方法。您不需要删除记录然后再次插入它们。插入操作的成本不亚于更新(实际上它取决于多种因素)。从 C# 代码更新记录的已经被禁止的想法是可怕的。相反,这样做:

Import the CSV file to additional, working table in the database.

不要忘记添加主键。如果您不需要更新的事务日志,请使用 TRUNCATE,或者只是 DROP 并重新创建工作表。这将比从中删除行快得多。也可以考虑使用 TEMPORARY 表。

Write a query to update the records in the original table by joining the records in the working/TEMPORARY table you just imported.

就是这样。

当然,您可以根据您的情况使用IsVisible 标志,但我认为不再需要它了。

【讨论】:

  • 感谢您的 cmets。我也想知道临时表和TRUNCATE。但是如果我截断的话,我不会有一个根本没有价格的时期吗?
  • 我的意思是在每次导入之前TRUNCATE 临时表;不是原来的。看...在旁边的桌子上执行所有肮脏的操作。一旦您在临时表中的 PK 旁边有了当前价格,就使用 INNER JOIN 对主表发出 UPDATE 语句到 PK 上的临时表。
猜你喜欢
  • 1970-01-01
  • 2015-02-02
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多