Sql server 为什么存储过程在简单DELETE语句上意外地获得优化超时?
数据仓库中有一个多步骤过程,它生成一个临时表,其中包含将为每个批处理的作业列表。通常这大约是5000个工作岗位。到财务汇总结束时,我们可能会看到大约500000条已处理的记录。我注意到,它的一小部分让我提前暂停了存储过程的这一部分的优化:Sql server 为什么存储过程在简单DELETE语句上意外地获得优化超时?,sql-server,performance,stored-procedures,Sql Server,Performance,Stored Procedures,数据仓库中有一个多步骤过程,它生成一个临时表,其中包含将为每个批处理的作业列表。通常这大约是5000个工作岗位。到财务汇总结束时,我们可能会看到大约500000条已处理的记录。我注意到,它的一小部分让我提前暂停了存储过程的这一部分的优化: DELETE jfs FROM DataWarehouse.dbo.JobFinancialSummary jfs -- Financials table (> 3,000,000 records with indices) IN
DELETE jfs
FROM DataWarehouse.dbo.JobFinancialSummary jfs -- Financials table (> 3,000,000 records with indices)
INNER JOIN #JobList jl ON jfs.JobID = jl.JobID -- List of Jobs being processed (avg. of 5,000 records)
INNER JOIN FiscalPeriod fp ON fp.ID = jfs.FiscalPeriodID -- Month Reference Table (about 1,000 records)
WHERE fp.[Status] IN (1,2) -- Last 2 months
最令人困惑的是,这是存储过程中一个相对简单的部分,所有连接都在索引上。我唯一的问题是,当优化器对此进行评估时,它是如何超时的。我的理解是,优化器为每个语句提供了自己的“预算”,但也许我遗漏了一些东西。为什么这里会超时?删除速度非常慢的原因有很多: 原因:
- 表可能包含CDC,启用了CT
- 表可能包含在delete操作之后工作的触发器
- 表可能包含FK引用、约束
- 表可能包含与该表关联的索引视图
- 首先,我们需要检查此表的事务性等
- 删除的方法有很多,显然批量删除速度更快。第一种也是最著名的方法是使用软删除属性标记这些记录,并在夜间脱机删除
- 禁用索引、FK约束,因为您将在功能上注意所有这些约束
- 如果不需要,禁用该表上的CT、CDC等 为索引视图创建脚本,然后删除与此表关联的索引视图
- 然后通过批删除,通过设置@rowCount或top batchsize,可以更快地删除任意数量的记录 删除前50000名--基于场景 来自表1 循环中
如果仍在白天进行在线删除,则标记为软删除,并在夜间作业中以非常小的批量运行删除操作删除速度非常慢的原因有很多: 原因:
- 表可能包含CDC,启用了CT
- 表可能包含在delete操作之后工作的触发器
- 表可能包含FK引用、约束
- 表可能包含与该表关联的索引视图
- 首先,我们需要检查此表的事务性等
- 删除的方法有很多,显然批量删除速度更快。第一种也是最著名的方法是使用软删除属性标记这些记录,并在夜间脱机删除
- 禁用索引、FK约束,因为您将在功能上注意所有这些约束
- 如果不需要,禁用该表上的CT、CDC等 为索引视图创建脚本,然后删除与此表关联的索引视图
- 然后通过批删除,通过设置@rowCount或top batchsize,可以更快地删除任意数量的记录 删除前50000名--基于场景 来自表1 循环中
如果仍在白天进行在线删除,则将其标记为软删除,并在夜间作业中以非常小的批运行删除操作可能会更快地隔离要先删除的行/条目,而不是在删除时加入 假设
id
是您的主键/标识,则类似于此:
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
SELECT jfs.ID
INTO #tmp
FROM DataWarehouse.dbo.JobFinancialSummary jfs -- Financials table (> 3,000,000 records with indices)
INNER JOIN FiscalPeriod fp ON fp.ID = jfs.FiscalPeriodID -- Month Reference Table (about 1,000 records)
WHERE fp.[Status] IN (1,2)
/* EXISTS IS FASTER THAN A JOIN, AVOIDS FANNING */
AND EXISTS (SELECT 1 FROM #JobList jl where jfs.JobID = jl.JobID) -- List of Jobs being processed (avg. of 5,000 records)
然后发出删除命令,例如:
DELETE TOP(1000) jfs
FROM DataWarehouse.dbo.JobFinancialSummary jfs
WHERE EXISTS (SELECT 1 FROM #tmp t WHERE jfs.ID=t.ID)
从这里开始,根据要删除的行数,您可能希望在一夜之间批量删除—任何超过5000行的内容都将升级为表锁,并且是批量删除的主要候选对象
我在这里写了一个关于如何完成大批量删除的相当流行的答案:
首先隔离要删除的行/条目可能比在删除时加入更快 假设
id
是您的主键/标识,则类似于此:
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
SELECT jfs.ID
INTO #tmp
FROM DataWarehouse.dbo.JobFinancialSummary jfs -- Financials table (> 3,000,000 records with indices)
INNER JOIN FiscalPeriod fp ON fp.ID = jfs.FiscalPeriodID -- Month Reference Table (about 1,000 records)
WHERE fp.[Status] IN (1,2)
/* EXISTS IS FASTER THAN A JOIN, AVOIDS FANNING */
AND EXISTS (SELECT 1 FROM #JobList jl where jfs.JobID = jl.JobID) -- List of Jobs being processed (avg. of 5,000 records)
然后发出删除命令,例如:
DELETE TOP(1000) jfs
FROM DataWarehouse.dbo.JobFinancialSummary jfs
WHERE EXISTS (SELECT 1 FROM #tmp t WHERE jfs.ID=t.ID)
从这里开始,根据要删除的行数,您可能希望在一夜之间批量删除—任何超过5000行的内容都将升级为表锁,并且是批量删除的主要候选对象
我在这里写了一个关于如何完成大批量删除的相当流行的答案:
好的观点。我可以说没有FKs、触发器、索引视图或约束(主键除外)。这是很好的观点。我可以说没有FK、触发器、索引视图或约束(主键除外)。如果提供了这些,这类问题可能会涉及更多内容:
表模式以及计数、涉及的表索引、查询的执行计划
这类问题可能会涉及更多内容,提供时:表模式以及计数、涉及的表上的索引、查询的执行计划