我有一张带有地理专栏的表格。我想根据查询结果为行的子集(~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
这个查询需要半个多小时。发生了什么事?