我有一个非常简单的查询,我正在通过运行临时测试来测试它。 执行计划表明,由于估计不当,数据正在溢出到 tempdb 中。 我无法解决出现的三个警告中的任何一个:操作员在执行过程中使用 tempdb 溢出数据,溢出级别为 1 和 1 溢出线程
所有表都有覆盖索引和最新统计数据。
我尝试过使用临时表、硬编码而不是变量、重新排序 WHERE 子句,甚至通过向 JOIN 添加过滤条件来消除 WHERE 子句。
我在每次执行后使用DBCC FREEPROCCACHE中的计划句柄清除了特定的查询计划,但每次迭代都会生成相同的计划。
查询返回 10,567 条不同的记录,因此它并不是很大。
对于如何避免数据泄漏有什么建议吗?
这里是查询计划的链接brentozar.com/pastetheplan/?id=HJ1v8G03C
DECLARE
@StartDate datetime = '01/01/2023',
@EndDate datetime = '12/31/2023 23:59:59';
Select
c.DonorTracCaseID,
optn.Number AS OPTN,
ti.OfferDateTime
From
dbo.[Case] c
INNER JOIN dbo.TriageReferral tr ON c.ID = tr.CaseID
INNER JOIN dbo.TriageImport ti ON tr.ID = ti.ID
INNER JOIN PotentialDonor.DonorNumber optn ON c.DonorTracCaseID = optn.DonorTracCaseId
INNER JOIN [Admin].ConfigureDonorNumber cdn ON optn.ConfigureDonorNumberId = cdn.ConfigureDonorNumberId
Where
tr.IsDuplicate = 0
AND ti.OfferDateTime >= @StartDate
AND ti.OfferDateTime <= @EndDate
AND cdn.NumberDescription = 'OPTN';
你能做的似乎不多。实际不正确的基数估计来自
DonorNumber
,可能是由于数据倾斜所致。
可能值得添加以下索引,或修改现有索引。请注意,它们是多列索引,因为您似乎有许多单列索引,这没什么用。
PotentialDonor.DonorNumber (ConfigureDonorNumberId, DonorTracCaseId) INCLUDE (Number)
dbo.TriageReferral (IsDuplicate, CaseID)
过滤索引或统计通常是
DonorNumber
上错误估计的解决方案,但不是一个选项,因为实际查找值来自 Admin.ConfigureDonorNumber
上的唯一联接。因此,索引视图可能是解决这个问题的唯一方法。
CREATE OR ALTER VIEW [Admin].v_Potential_ConfigureDonorNumber
WITH SCHEMABINDING
AS
SELECT
optn.DonorTracCaseId,
optn.Number
FROM PotentialDonor.DonorNumber optn
INNER JOIN [Admin].ConfigureDonorNumber cdn ON optn.ConfigureDonorNumberId = cdn.ConfigureDonorNumberId
WHERE cdn.NumberDescription = 'OPTN'
CREATE UNIQUE CLUSTERED INDEX CX ON v_Potential_ConfigureDonorNumber (NumberDescription, DonorTracCaseId)
然后将查询的最后两个连接更改为 just (注意使用
NOEXPAND
)
INNER JOIN [Admin].v_Potential_ConfigureDonorNumber optn WITH (NOEXPAND) ON c.DonorTracCaseID = optn.DonorTracCaseId
您的最后一个选择是认输并强制服务器分配更多内存,并在查询结束时这样做:
OPTION (MIN_GRANT_PERCENT = 1);
增加百分比,直到问题消失。