我在一个表上进行迭代的存储过程遇到了问题,它可以在几百行上正常工作,但是当表超过数千行时,它会使内存饱和并崩溃。
该过程应逐行迭代,并用从该行中另一列计算出的值填充一列。我怀疑是游标使程序崩溃,在其他问题上,我已经读过使用while循环,但我不是sql专家,因此我尝试从这些答案中尝试的示例无效。
CREATE PROCEDURE [dbo].[GenerateNewHashes]
AS
BEGIN
SET NOCOUNT ON;
DECLARE @module BIGINT = 382449983
IF EXISTS(SELECT 1 FROM dbo.telephoneSource WHERE Hash IS NULL)
BEGIN
DECLARE hash_cursor CURSOR FOR
SELECT a.telephone, a.Hash
FROM dbo.telephoneSource AS a
OPEN hash_cursor
FETCH FROM hash_cursor
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE dbo.telephoneSource
SET Hash = CAST(telephone AS BIGINT) % @module
WHERE CURRENT OF hash_cursor
FETCH NEXT FROM hash_cursor
END
CLOSE hash_cursor
DEALLOCATE hash_cursor
END
END
基本上,该存储过程旨在填充添加到现有表中的称为Hash的新列,当更新表的脚本结束时,新列将填充为NULL值,然后该存储过程应该填充每个空值,带有操作电话号码(这是一个bigint)%模块变量(也包括big int)。
除了更改为while循环外,还有什么可以使它使用更少的内存或只是不崩溃的方法?预先感谢。
答案 0 :(得分:2)
您可以执行以下操作:
WHILE 1=1
BEGIN
UPDATE TOP (10000) dbo.telephoneSource
SET Hash = CAST(telephone AS BIGINT)%@module
WHERE Hash IS NULL;
IF @@ROWCOUNT = 0
BEGIN
BREAK;
END;
END;
只要有Hash
个值,这就会更新NULL
,并且在没有记录更新时将退出。
添加过滤索引也可能很有用:
CREATE NONCLUSTERED INDEX IX_telephoneSource_Hash_telephone
ON dbo.telephoneSource (Hash)
INCLUDE (telephone)
WHERE Hash IS NULL;
它将加快查找速度以进行更新。但这可能不是必需的。
答案 1 :(得分:0)
这是在上面的注释中不使用游标就在循环中执行此操作的代码示例,并且如果将要更新的字段添加为IS NOT NULL到内部循环中,它将不会更新已完成的操作(在情况下,您需要重新启动该过程。
我没有在其中包括您的特定表,但是如果您需要我可以在其中添加它。
DECLARE @PerBatchCount as int
DECLARE @MAXID as bigint
DECLARE @WorkingOnID as bigint
Set @PerBatchCount = 1000
--Find range of IDs to process using yoru tablename
SELECT @WorkingOnID = MIN(ID), @MAXID = MAX(ID)
FROM YouTableHere WITH (NOLOCK)
WHILE @WorkingOnID <= @MAXID
BEGIN
-- do an update on all the ones that exist in the offer table NOW
--DO YOUR UPDATE HERE
-- include this where clause where ID is your PK you are looping through
WHERE ID BETWEEN @WorkingOnID AND (@WorkingOnID + @PerBatchCount -1)
set @WorkingOnID = @WorkingOnID + @PerBatchCount
END
SET NOCOUNT OFF;
答案 2 :(得分:0)
我只需添加计算列:
ALTER TABLE dbo.telephoneSource
ADD Hash AS (CAST(telephone AS BIGINT)%382449983) PERSISTED;