我正在使用SQL Server 2008并运行以下存储过程,需要将70毫米表从大约50个行“清理”到另一个表,id_col
为integer
(主要身份密钥) )
根据我最后一次运行,它使它工作正常,但预计会持续约200天:
SET NOCOUNT ON
-- define the last ID handled
DECLARE @LastID integer
SET @LastID = 0
declare @tempDate datetime
set @tempDate = dateadd(dd,-20,getdate())
-- define the ID to be handled now
DECLARE @IDToHandle integer
DECLARE @iCounter integer
DECLARE @watch1 nvarchar(50)
DECLARE @watch2 nvarchar(50)
set @iCounter = 0
-- select the next to handle
SELECT TOP 1 @IDToHandle = id_col
FROM MAIN_TABLE
WHERE id_col> @LastID and DATEDIFF(DD,someDateCol,otherDateCol) < 1
and datediff(dd,someDateCol,@tempDate) > 0 and (some_other_int_col = 1745 or some_other_int_col = 1548 or some_other_int_col = 4785)
ORDER BY id_col
-- as long as we have s......
WHILE @IDToHandle IS NOT NULL
BEGIN
IF ((select count(1) from SOME_OTHER_TABLE_THAT_CONTAINS_20k_ROWS where some_int_col = @IDToHandle) = 0 and (select count(1) from A_70k_rows_table where some_int_col =@IDToHandle )=0)
BEGIN
INSERT INTO SECONDERY_TABLE
SELECT col1,col2,col3.....
FROM MAIN_TABLE WHERE id_col = @IDToHandle
EXEC [dbo].[DeleteByID] @ID = @IDToHandle --deletes the row from 2 other tables that is related to the MAIN_TABLE and than from the MAIN_TABLE
set @iCounter = @iCounter +1
END
IF (@iCounter % 1000 = 0)
begin
set @watch1 = 'iCounter - ' + CAST(@iCounter AS VARCHAR)
set @watch2 = 'IDToHandle - '+ CAST(@IDToHandle AS VARCHAR)
raiserror ( @watch1, 10,1) with nowait
raiserror (@watch2, 10,1) with nowait
end
-- set the last handled to the one we just handled
SET @LastID = @IDToHandle
SET @IDToHandle = NULL
-- select the next to handle
SELECT TOP 1 @IDToHandle = id_col
FROM MAIN_TABLE
WHERE id_col> @LastID and DATEDIFF(DD,someDateCol,otherDateCol) < 1
and datediff(dd,someDateCol,@tempDate) > 0 and (some_other_int_col = 1745 or some_other_int_col = 1548 or some_other_int_col = 4785)
ORDER BY id_col
END
欢迎任何改进此程序运行时间的想法或指示
答案 0 :(得分:3)
是的,试试这个:
Declare @Ids Table (id int Primary Key not Null)
Insert @Ids(id)
Select id_col
From MAIN_TABLE m
Where someDateCol >= otherDateCol
And someDateCol < @tempDate -- If there are times in these datetime fields,
-- then you may need to modify this condition.
And some_other_int_col In (1745, 1548, 4785)
And Not exists (Select * from SOME_OTHER_TABLE_THAT_CONTAINS_20k_ROWS
Where some_int_col = m.id_col)
And Not Exists (Select * From A_70k_rows_table
Where some_int_col = m.id_col)
Select id from @Ids -- this to confirm above code generates the correct list of Ids
return -- this line to stop (Not do insert/deletes) until you have verified @Ids is correct
-- Once you have verified that above @Ids is correctly populated,
-- then delete or comment out the select and return lines above so insert runs.
Begin Transaction
Delete OT -- eliminate row-by-row call to second stored proc
From OtherTable ot
Join MAIN_TABLE m On m.id_col = ot.FKCol
Join @Ids i On i.Id = m.id_col
Insert SECONDERY_TABLE(col1, col2, etc.)
Select col1,col2,col3.....
FROM MAIN_TABLE m Join @Ids i On i.Id = m.id_col
Delete m -- eliminate row-by-row call to second stored proc
FROM MAIN_TABLE m
Join @Ids i On i.Id = m.id_col
Commit Transaction
Explaanation。
您有许多不是SARGable的过滤条件,即它们会强制对循环的每次迭代进行完整的表扫描,而不是能够使用任何现有索引。始终尝试避免将处理逻辑应用于表列值的过滤条件,然后再将其与其他值进行比较。这消除了查询优化器使用索引的机会。
您正在一次执行一个插入...更好地生成需要处理的PK ID列表(一次性完成),然后在一个语句中一次执行所有插入。