覆盖索引并摆脱 Key Lookup

Covering index and getting rid of Key Lookup

我有一个 SQL 语句,该语句为我提供了一个 Key Lookup,它吸收了下面这个查询的处理。由于它是 3 部分联合的一部分,因此最好不要使用键查找。

我的查询如下。

SELECT
   c.customerName,
   c.customerNumber,
   totals.TotalLoanAmount,
   totals.TotalCommitmentAmount,
   l.loanNumber,
   l.commitmentAmount,
   ed.amountThreshold,
   ex.exceptionId,
   IsNull(ex.reminderDateGracePeriod, ed.defaultReminderDateGracePeriod) AS gracePeriod,
   ex.reminderDate AS targetDate,
   IsNull(ex.exceptionState, 'N') AS exceptionState,
   ex.exceptionState AS GeneralExceptionState
FROM 
   exceptionDefinition AS ed 
INNER JOIN 
   exception AS ex ON ed.exceptionDefId = ex.exceptionDefId
                   AND ex.loanId IS NULL
INNER JOIN 
   customer AS c ON c.customerId = ex.customerId
LEFT OUTER JOIN 
   loan AS l ON l.loanId = ex.loanId
INNER JOIN 
   viewCustomerLoanTotals AS totals ON totals.customerId = c.customerId
WHERE 
   ed.requireReminderDate = 'Y'
   AND ex.statusType = 'required'

我试图为此设置一个覆盖索引,因为它在异常 table 的主键上的聚簇索引上进行键查找。

ExceptionId

这是我在使用 statusType 作为 where 子句的一部分选择的列上的覆盖索引。

CREATE NONCLUSTERED INDEX [IX_EXCEPTIONPROCESS_COVER] ON [dbo].[exception]
(
    [exceptionId] ASC,
    [loanId] ASC,
    [reminderDate] ASC,
    [reminderDateGracePeriod] ASC,
    [exceptionState] ASC
)
INCLUDE ([statusType]) ON [PRIMARY]

这对密钥查找根本没有任何影响。我试图强制它使用索引,但它变成了 91% 的资源,而不是我试图摆脱的 61%。

任何见解都会很棒

您正在获取一行并且您正在尝试优化查询。 61%(此查询的几乎所有工作都在这里完成)是相对于查询的整个查询计划而言的。您可以推动多少是有限制的。 - SQL 服务器引擎只投入它认为值得的工作(优化查询),并且将您的查询视为不值得投入大量精力的事情。

问题是您的索引不能真正用于连接。为了可用,索引中的第一个字段必须使您也加入 table 与(或存在于 where 子句中)。

INNER JOIN exception AS ex ON 
    ed.exceptionDefId = ex.exceptionDefId AND 
    ex.loanId IS NULL

您正在使用 exceptionDefId (+loanID) 加入 tables,但索引中没有:

CREATE NONCLUSTERED INDEX [IX_EXCEPTIONPROCESS_COVER] ON [dbo].[exception]
(
    [exceptionId] ASC,
    [loanId] ASC,
...

如果这个索引只针对这个 SQL,那么应该会更好:

CREATE NONCLUSTERED INDEX [IX_EXCEPTIONPROCESS_COVER] ON [dbo].[exception] (
    exceptionDefId,
    loanId,
    statusType
) include (
   exceptionId,
   reminderDateGracePeriod,
   reminderDate,
   exceptionState,
   customerId
)

索引中字段的顺序也应基于选择性(=每个键的平均行数最少)。对于包含无关紧要的字段。

根据 "output list",您的 "covering" 索引不包括 table 中正在使用的所有列。添加剩余的列。