我有以下存储过程,它删除并在表中插入行。它运行缓慢。
我已阅读各种提案,并已实施:
所以应该采取的方式是:
表中有大约1000万条记录。
每天我需要刷新约15-30%的人。我用这个SP做到了。
来源:
CREATE PROCEDURE [dbo].[spIncrementalUpdate]
-- Add the parameters for the stored procedure here
@table_inc nvarchar(30),
@table_target nvarchar(30),
@table_date nvarchar(30),
@field1 nvarchar(10),
@field2 nvarchar(10)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @logmessage as nvarchar(2048)
DECLARE @logdatacode as int
DECLARE @cmd as nvarchar(max)
DECLARE @fromjulian nvarchar(10)
DECLARE @datadate datetime
DECLARE @datadate_str nvarchar(10)
DECLARE @rows int
DECLARE @ParmDefinition nvarchar(500)
select @fromjulian = '114000'
print 'Using ' + @fromjulian
--
-- GET THE ROW COUNT OF THE INC TABLE.
--
IF @field2 = ''
BEGIN
SET @cmd = N'SELECT @retval = count(*) from ' +
@table_inc + ' where ' + @field1 +' > ' + @fromjulian
END
ELSE
BEGIN
SET @cmd = N'SELECT @retval = count(*) from ' +
@table_inc + ' where ' + @field1 +' > ' + @fromjulian +
' OR ' + @field2 +' > ' + @fromjulian
END
SET @ParmDefinition = N'@retval int OUTPUT'
EXEC sp_executesql @cmd, @ParmDefinition, @retval = @rows OUTPUT
--
if @rows <> 0
BEGIN
SET @logmessage = @table_inc + ' has ' +
cast(@rows as nvarchar(10)) +
' rows after ' + @fromjulian + ', deleting'
SET @logdatacode = 1000
--
-- Delete the records from original table based on @fromjulian
--
IF @field2 = ''
BEGIN
SET @cmd = N'delete ' + @table_target +
' from (select top(50000) * from ' + @table_target +
' where ' + @field1 + ' > ' + @fromjulian +
' order by ' + @field1 + ') ' +
@table_target
print @cmd
END
ELSE
BEGIN
SET @cmd = N'delete ' + @table_target +
' from (select top(50000) * from ' +
@table_target +
' where ' + @field1 + ' > ' + @fromjulian +
' OR ' + @field2 +' > ' + @fromjulian +
' order by ' + @field1 + ',' + @field2 + ') ' +
@table_target
print @cmd
END
SELECT 1
WHILE @@ROWCOUNT <> 0
BEGIN
EXEC sp_executesql @cmd
END
--
-- Inserting the records to target from INC table
--
IF @field2 = ''
BEGIN
SET @cmd = N'insert into ' + @table_target +
' select * from ' + @table_inc +
' where ' + @field1 +' > ' + cast(@fromjulian as nvarchar(10))
print @cmd
END
ELSE
BEGIN
SET @cmd = N'insert into ' + @table_target +
' select * from ' + @table_inc +
' where ' + @field1 +' > ' + cast(@fromjulian as nvarchar(10)) +
' OR ' + @field2 +' > ' + cast(@fromjulian as nvarchar(10))
print @cmd
END
print @cmd
EXEC sp_executesql @cmd
END
ELSE
BEGIN
SET @logmessage = 'NO ROWS IN ' + @table_inc + ' AFTER ' + cast(@fromjulian as nvarchar(10))
SET @logdatacode = 1001
END
--
-- LOG
--
INSERT INTO YLA_GROUP.[dbo].[sysssislog]
([event]
,[computer]
,[operator]
,[source]
,[sourceid]
,[executionid]
,[starttime]
,[endtime]
,[datacode]
,[databytes]
,[message])
VALUES
('spIncrementalUpdate','','','',NEWID(),NEWID(),getdate(),getdate(),@logdatacode,null,@logmessage)
print cast(@logdatacode as nvarchar(10)) + ' - ' + @logmessage
END
答案 0 :(得分:2)
由于您要批量删除行,因此应从子查询中删除ORDER BY
子句,因为这不是必需的。
以下是您脚本的摘录:
IF @field2 = ''
BEGIN
SET @cmd = N'delete ' + @table_target +
' from (select top(50000) * from ' + @table_target +
' where ' + @field1 + ' > ' + @fromjulian + ') ' + @table_target
print @cmd
END
ELSE
BEGIN
SET @cmd = N'delete ' + @table_target +
' from (select top(50000) * from ' + @table_target +
' where ' + @field1 + ' > ' + @fromjulian +
' OR ' + @field2 +' > ' + @fromjulian + ') ' + @table_target
print @cmd
END
请记住,排序可能是一项昂贵的操作,如果删除(在这种情况下正确)索引,则排序会更加昂贵。
除此之外,你无能为力。还要考虑使用动态SQL,执行计划不缓存。因此,每次在@cmd
内执行命令时,查询引擎都需要计算最佳执行计划。不幸的是,据我所知,你需要动态SQL。