在后台运行MS SQL大型查询(Running large queries in the backg

2019-10-17 20:29发布

我使用MS SQL Server 2008中我有一个表,它是不断地使用(数据总是在不断变化,并插入到它),它现在包含〜70个密尔行,我想用存储过程运行在该表的简单查询应适当休息几天,

我需要的表来是可用的,现在我在执行存储过程,一段时间后通过身份查询每一个简单的选择,我尝试在表上执行不响应/运行了太多的时间,我打破它

我该怎么办? 这里是我的存储过程看起来像:

 SET NOCOUNT ON;
update SOMETABLE
set
[some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
WHERE 
[some_col] = 243

即使我与此尝试的where子句(用“和”逻辑..):

ID_COL > 57000000 and ID_COL < 60000000 and

它仍然无法正常工作

BTW- SomeFunction做一些简单的数学操作和查找行中包含约30万项的另一个表,但从来没有改变过

Answer 1:

从我的角度来看你的服务器有一个严重的性能问题。 即使我们假设在查询中没有一个记录

select some_col with (nolock) where id_col between 57000000 and 57001000

在内存,它不应该采取21秒内从磁盘顺序读取的几页(你对id_col聚集索引不应该被割裂,如果它是一个自动的身份和你没有做一些笨的像添加一个“递减”到索引定义)。

但是,如果你不能/不会解决这个问题,我的建议是做像100-1000记录一次小包装的更新(取决于查找功能多少时间消耗)。 一个更新/事务应该不超过30秒。

你看,每个更新不断修改它,直到交易完成后,所有记录的独占锁。 如果不使用显式事务,每个语句在一个单一的,自动的事务上下文中执行,因此当更新语句进行锁得到释放。

但你仍然可以运行到死锁这种方式,这取决于其他进程做。 如果他们在同一时间修改多条记录,也或者即使他们收集并保持几行读锁,你可以死锁。

为了避免死锁,您的更新语句需要采取锁定所有将在一次修改记录。 做到这一点的方法是将一个更新语句(由id_col限制只有几行)的串行事务样

IF @@TRANCOUNT > 0
  -- Error: You are in a transaction context already

SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

-- Insert Loop here to work "x" through the id range
  BEGIN TRANSACTION
    UPDATE SOMETABLE
      SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
      WHERE [some_col] = 243 AND id_col BETWEEN x AND x+500 -- or whatever keeps the update in the small timerange
  COMMIT
-- Next loop

-- Get all new records while you where running the loop. If these are too many you may have to paginate this also:
BEGIN TRANSACTION
  UPDATE SOMETABLE
    SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
    WHERE [some_col] = 243 AND id_col >= x
COMMIT

每次更新这需要在给定的记录更新/独家键范围锁(但只有他们,因为你限制通过聚集索引键更新)。 它会等待在相同的记录任何其他更新来完成,然后把它的锁(导致阻塞对所有其他交易,但仍然只为给定的记录),然后更新记录,并解除锁定。

最后一个额外的声明是非常重要的,因为这将需要一个键范围锁定为“无限”,从而防止甚至刀片上,而更新语句运行范围的结束。



文章来源: Running large queries in the background MS SQL