【问题标题】:Select from table during update更新期间从表中选择
【发布时间】:2014-01-16 16:22:08
【问题描述】:

我有一个正在更新的表,更新本身需要 8 秒才能完成。当用户进来时,我需要更新表格并向他们展示表格中的总和:

查询

SELECT Jaccard/(SELECT SUM(Jaccard) FROM PreProcessed)
FROM PreProcessed
WHERE MinX = 25 AND MinY = 25
AND MaxX = 26 AND MaxY = 26

问题是多个用户可以同时进来,UPDATE语句的X锁意味着我不能长时间从表中读取。

我想知道我应该使用什么类型的LOCK 来允许查询能够在更新发生时从先前提交的数据中获取SELECT?我最初想使用READCOMMITTED,但它似乎没有达到我想要的效果。我想要更新前的数据,而不是部分提交的数据。

存储过程

set statistics time ON

DECLARE @MinX INT = 0;
DECLARE @MinY INT = 0;
DECLARE @MaxX INT = 50;
DECLARE @MaxY INT = 50;

DECLARE @Lambda DECIMAL(10, 5) = 0.5;
DECLARE @ReverseLambda DECIMAL(10, 5) = 1 - @Lambda;

DECLARE @Area INT = (@MaxX - @MinX) * (@MaxY - @MinY);

UPDATE PreProcessed
SET Jaccard = (@ReverseLambda * Jaccard) + (@Lambda * dbo.fn_ComputeJaccard(@MinX, @MinY, @MaxX, @MaxY, @Area, MinX, MinY, MaxX, MaxY))
FROM PreProcessed

set statistics time off

如果有的话,我可以做些什么来允许在我的更新期间发生读取?

编辑

select CAST(1 AS DECIMAL(38, 28))/CAST(1625625 AS DECIMAL(38, 28))

select CAST(1 AS DECIMAL(20, 10))/CAST(1625625 AS DECIMAL(20, 10))

【问题讨论】:

  • 如果您对脏读没问题,您可以尝试将事务隔离级别设置为未提交读:stackoverflow.com/questions/2471055/…
  • @Dan - 脏读是禁忌。我真的需要它尽可能地读取以前提交的数据(在整个更新之前)。我什至考虑过使用临时表,但合并需要 12 秒...这再次锁定了表...

标签: sql sql-server-2008 select locking sql-update


【解决方案1】:

这是您需要非规范化的时候之一。创建表

create table PreProcessedTotal (
   JaccardTotal decimal(18, 4) not null
)

(替换适当的数据类型)。您需要在 PreProcessed 表中添加三个触发器:

  • 一个插入触发器,用于在新行中添加 Jaccard 的值
  • 更新,添加插入的值并减去删除的值
  • 用于减去已删除值的删除触发器

然后您可以使用:

select Jaccard / JaccardTotal
from Preprocessed with (nolock)
cross join PreProcessedTotal with (nolock)

with (nolock) 可能不需要。您还需要在 PreProcessedTotal 表上线时使用当前总数填充它。

【讨论】:

  • 哇...哇...虽然我还没有实现这个,但它是一个很好的解决方案!起初我担心脏读,但显然这不是问题。我很高兴我发布了这个问题,我几乎用READPAST 锁妥协了! :)
  • 我假设 8 秒的大部分时间都用于进行表扫描以获取 SUM。您还应该检查查询的效率,而不需要对 Min/Max 值求和,如果效率不高,请在这些列上添加索引。
  • 快速问题...为什么当我这样做时:Jaccard/JaccardTotal 它返回零,但是当我使用 SUM 它返回正确的值? JaccardTotal 是DECIMAL(38,28)...
  • 我不知道;只要使用 SUM 的最小/最大值相同或不应该没有任何区别。你确定这些值是一样的吗?它可以返回 0 的唯一方法是 Jaccard 为 0;如果 JaccardTotal 为零,则会出错。
  • PS 你也可以在同一个查询中分别选择 Jaccard 和 Jaccard Total 来查看它得到了什么以及计算出来的数字。
猜你喜欢
  • 2019-12-19
  • 2020-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-07
相关资源
最近更新 更多