我有一个用例,我需要遍历表中的所有行并对每一行应用一些转换(也更新)。
以下是我现在的做法:
注意:存储过程有一些验证检查和一个更新语句,它将针对所有 150k 记录运行。
问题是处理所有 150k 行需要花费近 3.5 小时,这可能是不可接受的,因为我可能必须至少每 2 小时运行一次此过程。
我也尝试过使用脚本任务,并在脚本任务中,使用 ADO.NET 迭代对象值,但所花费的时间几乎相同 3 个多小时。
还有 150k 行的表没有主键标识。
请帮助我如何提高此过程的性能。
详细信息:下面是执行 SQL 任务,它从包含 150k 记录的表中获取 4 列并将其存储在对象类型变量中。
select aa, bb, cc, dd
from xxxx;
(假设 xxxx 表有 150000 行要处理)
然后我使用这个 foreach 循环容器来迭代表 xxxx 中总共 150 000 行中的每一行
现在我使用“执行SQL任务”来调用包含逻辑的存储过程;存储过程接受 4 个参数并逐行处理它们,直到 foreach 循环耗尽。
存储过程看起来像这样
CREATE PROCEDURE [Omg].[validateError]
@DID varchar(50),
@MGN varchar(100),
@MN varchar(50),
@SN varchar(20)
AS
DECLARE @IsValidxx bit = 0,
@IsValidyy bit = 0,
@IsValidzz bit = 0,
@IsValidww bit = 0,
@HoldErrorCodes varchar(20) = 'Z',
@InValidxxrErrorCode varchar(20) = 'D',
@InValidyyErrorCode varchar(20) = 'A',
@InValidzzErrorCode varchar(20) = 'M',
@InValidwwErrorCode varchar(20) = 'G';
BEGIN
BEGIN TRY
SET @IsValidxx = CASE
WHEN EXISTS(SELECT 1 FROM aaaaaaaa WHERE DID = @DID AND TerritoryType = 'Level 1')
THEN 1
ELSE 0
END;
SET @IsValidyy = CASE
WHEN EXISTS (SELECT 1
FROM bbbbbbb OFM
INNER JOIN ccccccc MG ON MG.Ordf = OFM.Ordf
INNER JOIN ddddddddd M ON M.Mod = MG.Mod
AND M.Available = 1
AND MG.IsActive = 1
AND M.MN = @MN
AND MG.MGN = @MGN)
THEN 1
ELSE 0
END;
IF @IsValidyy = 1
BEGIN
SET @IsValidzz = 1;
SET @IsValidww = 1;
END
ELSE
BEGIN
SET @IsValidzz = CASE WHEN EXISTS(SELECT 1 FROM dddddd WHERE MN = @MN AND SN=@SN AND Available=1 ) THEN 1 ELSE 0 END;
SET @IsValidww= CASE WHEN EXISTS(SELECT 1 FROM ccccc] WHERE MGN = @MGN AND IsActive=1) THEN 1 ELSE 0 END;
END
IF @IsValidxx = 1 AND @IsValidyy = 1 AND
@IsValidzz = 1 AND @IsValidww = 1
BEGIN
SET @IsValidxx = 1;
SET @IsValidyy = 1;
SET @IsValidzz = 1;
SET @IsValidww = 1;
END
ELSE
IF @IsValidxx = 0
BEGIN
SET @HoldErrorCodes = @HoldErrorCodes + @InValidxxrErrorCode;
END
IF @IsValidyy = 0
BEGIN
SET @HoldErrorCodes = @HoldErrorCodes + @InValidyyErrorCode;
END
IF @IsValidzz = 0
BEGIN
SET @HoldErrorCodes = @HoldErrorCodes + @InValidzzErrorCode;
END
IF @IsValidww = 0
BEGIN
SET @HoldErrorCodes = @HoldErrorCodes + @InValidwwErrorCode;
END
UPDATE [Import].[Recommendation]
SET ErrorCodes = @HoldErrorCodes
WHERE DID = @DID
AND MN = @MN
AND MGN = @MGN
AND SN = @SN;
END TRY
BEGIN CATCH
RETURN ERROR_MESSAGE() ;
END CATCH
整个过程需要3个多小时才能处理150k条记录
你应该能够做这样的事情:
update secondValidation
set ErrorCodes = concat(
case when isvalidxx = 0 then @InValidxxrErrorCode end
,case when isvalidyy = 0 then @InValidyyrErrorCode end
,case when isvalidzz = 0 then @InValidzzrErrorCode end
,case when isvalidww = 0 then @InValidwwrErrorCode end
)
--select *
from (
select *
, case
when IsValidYY = 1 THEN 1
ELSE CASE WHEN EXISTS(SELECT 1 FROM dddddd WHERE MN = t.MN AND SN=t.SN AND Available=1 ) THEN 1 ELSE 0 END
END AS IsValidzz
, case
when IsValidYY = 1 THEN 1
ELSE CASE WHEN EXISTS(SELECT 1 FROM [ccccc] WHERE MGN = t.MGN AND IsActive=1) THEN 1 ELSE 0 END
END AS IsValidww
from (
select *
, IsValidxx = CASE
WHEN EXISTS(SELECT 1 FROM aaaaaaaa WHERE DID = t.ID -- ??
AND TerritoryType = 'Level 1')
THEN 1
ELSE 0
END
, IsValidyy = CASE
WHEN EXISTS (SELECT 1
FROM bbbbbbb OFM
INNER JOIN ccccccc MG ON MG.Ordf = OFM.Ordf
INNER JOIN ddddddddd M ON M.Mod = MG.Mod
AND M.Available = 1
AND MG.IsActive = 1
AND M.MN = t.MN -- ??
AND MG.MGN = t.MGN) -- ??
THEN 1
ELSE 0
END
from yourmaintable t
) firstValidation
) secondValidation
where IsValidxx + IsValidyy + IsValidzz + IsValidww <> 4
只需将变量连接替换为针对主表的连接,就可以开始了。