Ada*_*kis 5 sql-server index-tuning sql-server-2012 nonclustered-index filtered-index
我试图理解为什么非聚集索引在过滤时不适用于给定的查询。我的(大)查询的相关部分是这样的:
) results
JOIN BE_Insurance ins
ON results.PayorId = ins.Id
Run Code Online (Sandbox Code Playgroud)
在选择中,我只抓取 ins.name。我最初创建的索引是这样的:
CREATE INDEX IX_BE_Insurance_PayorId_PayorName
ON BE_Insurance (Id) INCLUDE (Name)
WHERE ParentId IS NULL
Run Code Online (Sandbox Code Playgroud)
我的查询是这样的,只有带有 NULL parentId 的 payorIds 才会被选择,但我理解优化器不愿意选择它。但是当我添加一个提示来尝试强制索引时,整个事情就出错了。
由于此查询中定义的提示,查询处理器无法生成查询计划。在不指定任何提示且不使用 SET FORCEPLAN 的情况下重新提交查询。
我认为它会遵循我的提示,如果我发现一些错误的数据并且索引缺少一些所需的值,则可能会在执行时出错。从索引中删除过滤器会导致查询成功选择它(即使没有提示)。
带有 WHERE 子句的索引不适合这样的查询吗?只有当优化器可以保证过滤器有效并且不会产生任何缺失值时,它们才符合条件吗?
根据要求,这是整个查询,仍在进行中。
SELECT results.*
FROM (
SELECT auths.*,
worked.WorkedHours,
worked.WorkedUnits,
worked.WorkedAmount,
worked.ActiveClients
FROM (
SELECT PayorId,
SUM(AuthHours) AuthHours,
SUM(AuthUnits) AuthUnits,
SUM(AuthAmount) AuthAmount
FROM (
--DYNAMIC TEMPLATE ----------------------------------------------------------------------------------
SELECT PayorId,
PayorName,
AuthHours AuthHours,
AuthUnits AuthUnits,
AuthAmount AuthAmount
FROM PayorAuthorizations_Level1Data_Authorizations auths WITH(NOEXPAND)
WHERE OrganizationId = @organizationId AND StartDate <= @endDate AND @startDate <= EndDate
--/DYNAMIC TEMPLATE----------------------------------------------------------------------------------
--INTERSECT / EXCEPT dynamically generated queries
) q
GROUP BY PayorId
) auths
JOIN (
SELECT PayorId,
SUM(ISNULL(TotalWorkedHours, 0)) WorkedHours,
SUM(ISNULL(TotalWorkedUnits, 0)) WorkedUnits,
SUM(ISNULL(TotalWorkedAmount, 0)) WorkedAmount,
COUNT(DISTINCT clientId) ActiveClients
FROM (
--DYNAMIC TEMPLATE ----------------------------------------------------------------------------------
SELECT PayorId,
TotalWorkedHours,
TotalWorkedUnits,
TotalWorkedAmount,
clientId clientId
FROM PayorAuthorizations_Level1Data_CurrentlyWorked worked WITH(NOEXPAND)
WHERE OrganizationId = @organizationId AND StartDate <= @endDate AND @startDate <= EndDate
--/DYNAMIC TEMPLATE----------------------------------------------------------------------------------
--INTERSECT / EXCEPT other dynamically generated queries
) q
GROUP BY PayorId
) worked
ON auths.payorId = worked.payorId
) results
JOIN BE_Insurance ins WITH (INDEX(IX_BE_Insurance_PayorId_PayorName))
ON results.PayorId = ins.Id
OPTION(FORCE ORDER, MERGE JOIN)
Run Code Online (Sandbox Code Playgroud)
我认为它会遵循我的提示,如果我发现一些错误的数据并且索引缺少一些所需的值,则可能会在执行时出错。
如果查询优化器可以保证(在其推理框架内)可以从索引中提供所有可能的匹配项,则查询优化器将仅在查询计划中使用过滤索引。这是设计使然,以避免您描述的那种运行时错误。
未能从我的非聚集索引针对聚集索引键查找导致嵌套循环联接,大概是为了获取 parentId。INCLUDING parent ID 消除了这一点,并给我留下了一个很好的非聚集索引扫描。
这是一个已知的电流限制。将过滤的列添加到键或包含列表是标准的解决方法,并且是针对各种半相关原因的当前最佳实践。
虽然肯定需要 FORCE ORDER, MERGE JOIN。
除非您完全理解所有后果,否则使用这样的提示(指令)要非常小心。FORCE ORDER特别是一个非常强大和广泛的提示,具有许多不明显的副作用,包括聚合运算符的放置,以及子查询和公共表表达式的计算顺序。
在大多数情况下,您应该尝试编写为查询优化器提供足够高质量信息的查询,以便在没有提示的情况下做出正确的决策。暗示的计划今天可能是“最佳”的,但随着数据量和/或分布随时间的推移而变化,它可能不会保持不变。