Dan*_*vey 16 sql-server delete execution-plan sql-server-2016 query-performance
我正在使用 Microsoft SQL Server 2016 (SP2-CU11) (KB4527378) - 13.0.5598.27 (X64) Nov 27 2019 18:09:22 版权所有 (c) Windows Server 2012 R2 上的 Microsoft Corporation 标准版(64 位)标准 6.3(内部版本 9600:)
该服务器位于 SSD 驱动器上,最大内存为 128 GB。Parallelism 的 CostTheshold 是 70,MaxDegree of Parallelism 是 3。
我有一个“行程”表,它由 23 个外键引用,带有 ON DELETE CASCADE 选项。
这个表本身并没有那么大(530 万行,1.3 GB 数据)。但是在 23 个引用的表中,有两个表非常大(超过 10 亿行,每行 54 和 69 GB)。
问题是当我们尝试删除“Trips”表中的少量行(假设为 4 行)时,SQL 估计将要删除这么多行,它需要 10GB 的 RAM,估计将有数百万行返回,并锁定表。一切都停止,其他查询阻塞,应用程序超时。
以下是 1 个删除语句的主表和行数:
表 EventConditions 和 ProfileRanges 各有超过 10 亿行。
这是计划缓存:https : //www.brentozar.com/pastetheplan/?id=HJNg5I0BU
当我查看 SentryOne 计划资源管理器时,我可以看到 SQL 正在读取整个表,即使“表假脱机”然后过滤并只保留 2012 行 ProfileRanges 和 EventConditions 大致相同。
当我使用 Brent Ozar 的 sp_blitzCache 过程查看查询的内存授予时,我可以看到该查询需要大约 10gb 的 RAM。
之后,查询要么等待 SOS_SCHEDULER_YIEL(因此等待 4 毫秒后轮到它使用 CPU)或 MEMORY_ALLOCATION_EXT。程序超时并失败。
我能做些什么来完成这项工作?
我想到的一件事是删除两个最大表上的外键,并在而不是触发器中删除它们的行。但我不喜欢使用触发器而不是外键来强制执行数据库一致性。
任何建议或帮助将不胜感激
ProfileRanges 的主键是
EventConditions 的主键是
Pau*_*ite 17
假设所有相关表对删除路径都有正确的索引,您可以尝试:
DELETE [Trips]
WHERE [ISAFileName]='ID_774199_20200311_133117.isa'
OPTION (LOOP JOIN, FAST 1, USE HINT ('FORCE_LEGACY_CARDINALITY_ESTIMATION'));
Run Code Online (Sandbox Code Playgroud)
如果可行,请尝试将其减少到最少的提示数。
这些类型的计划对于基数估计非常具有挑战性,并且“默认”CE 模型通常会造成混乱。
一旦您有了一个运行良好的计划形状,您应该能够在必要时使用计划指南等强制该形状。
级联删除表扫描是表上没有正确索引的常见症状。
确保所有 FK 表都有支持外键的索引。即以 FK 列作为其他表索引中的前导列的聚集或非聚集索引。
例如
create index ix_TripId on EventConditions (TripId)
Run Code Online (Sandbox Code Playgroud)
并考虑 TripID FK 列是否不应该是聚集索引中的前导列,例如:
create table EventConditions
(
TripId int not null,
EventId bigint not null,
EventConditionDefId int not null,
constraint pk_EventConditions
primary key clustered(TripId, EventId, EventConditionDefId),
...
)
Run Code Online (Sandbox Code Playgroud)
这将优化每个表以供 TripId 访问。
此外
我想到的一件事是删除两个最大表上的外键,并在而不是触发器中删除它们的行。
您不需要删除 FK。只需先从子表中删除,并可能从 FK 中删除 ON DELETE CASCADE 以要求先删除子表。这将首先加载带有要在每个级别删除的键值的临时表,然后从上到下加载它们。
create table #tripIdsToDelete(TripId int primary key)
insert into #tripIdsToDelete ...
create table #EventIdsToDelete(EventId int primary key)
insert into #EventIdsToDelete(EventID)
select EventId from Events
where TripId in (select TripId from #tripIdsToDelete)
...
create table #EventConditionIdsToDelete ...
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2713 次 |
最近记录: |