从循环更新(表锁定问题+ CLR内存问题)

时间:2015-11-12 14:33:13

标签: sql sql-server sql-server-2012 spatial

我有一张带有地理专栏的表格。我想根据查询结果为行的子集(~1,000)更新此值。

我创建了一个视图,它将返回我想要的地理列+要更新的表中行的ID。

如果我运行查询

UPDATE A
SET A.GeogCol = B.GeogCol
FROM TableToUpdate A
INNER JOIN UpdatedFrom_View B
ON A.ID = B.ID

我将收到系统内存不足错误。这是因为它是32位sql server并且VAS预留空间不足,因为我调用了创建地理列的CLR函数。我不是服务器管理员,因此我无法暂时为VAS预留分配更多空间。

如果我将其减少到WHERE A.ID BETWEEN 0 AND 100并尝试手动迭代,我有时会遇到此问题。我发现了一些麻烦的行(比平时更大的地理对象),如果我说WHERE A.ID = @ID,我可以更新它们。

我的想法是根据循环更新。

DECLARE @ID INT
DECLARE @g GEOGRAPHY

DECLARE IDCursor CURSOR FOR SELECT ID FROM TableToUpdate
OPEN IDCursor

FETCH NEXT FROM IDCursor INTO @ID

WHILE @@FETCH_STATUS = 0
BEGIN
  SET @g = (SELECT GeogCol FROM UpdatedFrom_View WHERE ID = @ID)
  UPDATE TableToUpdate SET GeogCol = @g WHERE ID = @ID
  FETCH NEXT FROM IDCursor INTO @ID
END
CLOSE IDCursor
DEALLOCATE IDCursor

然而,这似乎与表锁定有关(我认为)。它现在已经运行了不到2天,并且已经更新了不到150条记录。

作为参考,手动完成后,UPDATE TableToUpdate SET GeogCol = @g WHERE ID = @ID只需不到10秒。

有更好的方法吗?

- 编辑

所以我决定测试一下。

我写了这个查询大约需要1秒钟。

UPDATE A
SET A.GeogCol = B.GeogCol
FROM TableToUpdate A
INNER JOIN UpdatedFrom_View B
ON  A.ID = B.ID
WHERE A.ID BETWEEN 1 AND 1

然后我编写了一个执行完全相同的存储过程。

CREATE PROCEDURE TestUpdate @IDLow INT, @IDHigh INT
AS
BEGIN
  UPDATE A
  SET A.GeogCol = B.GeogCol
  FROM TableToUpdate A
  INNER JOIN UpdatedFrom_View B
  ON  A.ID = B.ID
  WHERE A.ID BETWEEN @IDLow AND @IDHigh
END

GO

EXEC TestUpdate @IDLow = 1, @IDHigh = 1

这个查询需要半个多小时。发生了什么事?

0 个答案:

没有答案