索引中包含列的硬性和快速规则

38 index sql-server-2005 sql-server-2008 sql-server

是否有任何硬性规则来决定应该将哪些列以及应该以何种顺序放置在 Included in non-clustered index 中。我刚刚读了这篇文章/sf/ask/91559331/ 我发现以下查询:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5
Run Code Online (Sandbox Code Playgroud)

海报建议制作这样的索引:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)
Run Code Online (Sandbox Code Playgroud)

我的问题来了,为什么我们不能像这样制作索引

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)
Run Code Online (Sandbox Code Playgroud)

或者

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)
Run Code Online (Sandbox Code Playgroud)

以及是什么导致发布者决定保留姓氏列。为什么不是其他列?以及如何决定我们应该以什么顺序保留列?

gbn*_*gbn 48

marc_s 的索引建议是错误的。我添加了评论。(这也是我接受的答案!)

此查询的索引将是

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)
Run Code Online (Sandbox Code Playgroud)

一个索引通常是

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)
Run Code Online (Sandbox Code Playgroud)

在哪里:

  • KeyColList = 关键列 = 用于行限制和处理
    WHERE、JOIN、ORDER BY、GROUP BY 等
  • NonKeyColList = 非键列 = 在选择/限制后用于 SELECT 和聚合(例如 SUM(col))


小智 19

JNK 和 gbn 给出了很好的答案,但也值得考虑大局 - 而不仅仅是关注单个查询。尽管此特定查询可能会受益于索引 (#1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)
Run Code Online (Sandbox Code Playgroud)

如果查询稍有变化,则此索引根本没有帮助,例如:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'
Run Code Online (Sandbox Code Playgroud)

这将需要索引(#2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)
Run Code Online (Sandbox Code Playgroud)

假设您在第 5 部门有 1,000 名员工。使用索引 #1,要查找所有 Smiths,您需要在第 5 部门中查找所有 1,000 行,因为包含的列不是键的一部分。使用索引 #2,您可以直接查找部门 5,LastName Smith。

因此,索引 #2 在服务更广泛的查询时更有用——但代价是索引键更加臃肿,这将使索引的非叶页更大。每个系统都会有所不同,因此这里没有经验法则。


作为旁注,值得指出的是,如果 EmployeeID 是该表的聚集键 - 假设有聚集索引 - 那么您不需要包含 EmployeeID - 它存在于所有非聚集索引中,这意味着索引 #2 可以只是是

Employee(DepartmentID, LastName)
Run Code Online (Sandbox Code Playgroud)

  • +1 获取更多有用信息。对于您的最后一点,我对此进行了测试,如果 EmployeeID 是聚集索引,则实际上会忽略 INCLUDE 中 EmployeeID 的显式使用(基于索引的大小)。虽然我认为它更明显并且没有空间缺点。 (2认同)

JNK*_*JNK 7

我不确定你是如何得到第一个的。对我来说,对于那个查询,我会使用:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)
Run Code Online (Sandbox Code Playgroud)

SQL 中的几乎所有内容都没有“硬性规定”。

但是,对于您的示例,索引将使用的唯一字段是DepartmentID因为它在WHERE子句中。

其他字段只需要从那里轻松访问即可。您选择基于DepartmentID然后INCLUDE在索引的叶节点具有那些字段。

您不想使用其他示例,因为它们不适用于此索引。

把索引想象成电话簿。大多数电话簿按姓氏、名字、中间名首字母排序。如果您知道某人的名字,但不知道他们的姓氏,则电话簿对您没有好处,因为您无法根据电话簿索引的顺序搜索名字。

这些INCLUDE字段就像电话号码、地址等书籍中每个条目的其他信息。

编辑:

进一步阐明为什么不使用:

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)
Run Code Online (Sandbox Code Playgroud)

此索引仅在您的子句中具有EmployeeIDBOTH EmployeeID and时才有用。这几乎与此查询所需的内容相反LastNameWHERE