2

假设我有下表:

Orders
======
OrderID
CustomerID
StatusID
DateCreated

我有以下查询:

select CustomerID from Orders where OrderID = 100

select OrderID from Orders where CustomerID = 20

select OrderID, StatusID from Orders where CustomerID = 100 and OrderID = 1000

如果我制作以下索引:

create nonclustered index Example
  On dbo.Orders(OrderID,CustomerID)
  Include(StatusID)

这是否会使用一个索引优化所有 3 个查询?换句话说,复合索引是否改进了使用复合中的一项的查询?或者是否也应该在这些列上创建单独的索引(即 OrderID、CustomerID)以满足查询 1 和 2?

4

3 回答 3

6

该索引对第二次查询没有帮助,因为不可能首先在索引中最左边的列上查找。

想想电话簿。首先,尝试查找姓氏为 Smith 的所有人。容易,对吧?现在,尝试查找所有名字为 John 的人。电话簿中“索引”的工作方式是姓氏、名字。当您尝试查找所有 John 时,首先按 LastName 对它们进行排序根本没有帮助 - 您仍然需要查看整个电话簿,因为会有 John Anderson 和 John Zolti 以及介于两者之间的所有内容。

为了充分利用所有三个查询,并假设这些是唯一正在使用的三个查询表单,我可能建议一个额外的索引:

create nonclustered index Example2
  On dbo.Orders(CustomerID) INCLUDE(OrderID)

(如果 OrderID 是主键,则不需要包含它。)

但是,这应该针对您的工作负载进行测试,因为索引不是免费的——它们确实需要额外的磁盘空间,并且在您运行 DML 查询时需要维护额外的工作。同样,这假设您的问题中列出的三个查询是您使用的唯一形状。如果您有其他查询具有不同的输出列或不同的 where 子句,那么所有的赌注都会被取消。

于 2012-07-18T18:49:05.700 回答
3

以上答案都是正确的。但他们遗漏了一件事。您可能需要 ORDER_ID 上的聚集索引。如果您在 ORDER_ID 上创建聚集索引,则表上的任何非聚集索引都将自动包含该值,因为非聚集索引条目指向存在聚集索引的表上的聚集索引。所以你会想要这个:

create clustered index IX_ORDERS_ORDERID on ORDERS (OrderID)
go
create nonclustered index IX_ORDERS_CustomerID
On dbo.Orders(CustomerID)
Include(StatusID)
go

现在您可以快速搜索订单 ID 或客户 ID,并且您的所有查询都将运行良好。你知道怎么看执行计划吗?在 sql studio 中去查询 - 包括实际的执行计划,然后运行您的查询。您将看到使用了哪些索引、是否执行了查找或扫描等的图形表示。

于 2012-07-18T19:20:32.653 回答
1
create nonclustered index Example
  On dbo.Orders(OrderID,CustomerID)
  Include(StatusID)

将此索引读取为:从 Orders 表中创建 OrderID、CustomerID、StatusID 的系统维护副本。按 OrderID 订购此副本,并与 CustomerID 断绝关系。

select CustomerID from Orders where OrderID = 100

由于索引是按 OrderID 排序的,因此查找第一个符合条件的记录很快。一旦我们找到第一条记录,我们可以继续在索引中读取,直到找到 OrderID 不是 100 的记录。然后我们可以停止。由于我们想要的所有列都在索引中,我们不必查找实际的表。伟大的!

select OrderID from Orders where CustomerID = 20

由于索引按 OrderID 排序,然后按 CustomerID 排序,因此符合条件的记录可以出现在索引中的任何位置。第一条记录可能符合条件(OrderID = 1,CustomerID = 20)。最后一条记录可能符合条件(OrderID = 1000000000,CustomerID = 20)。我们必须阅读整个索引才能找到符合条件的记录。这是不好的。 一个小帮助:因为我们想要的所有列都在索引中,所以我们不必查找实际的表。因此,从技术上讲,第二个查询得到了索引的帮助——只是没有到其他查询得到帮助的程度。

select OrderID, StatusID from Orders where CustomerID = 100 and OrderID = 1000 

由于索引是按 OrderID 然后按 CustomerID 排序的,因此查找第一个符合条件的记录很快。一旦我们找到第一条记录,我们就可以继续在索引中读取,直到找到一条不合格的记录。然后我们可以停下来。由于我们想要的所有列都在索引中,我们不必查找实际的表。伟大的!


复合索引是否改进了使用复合中的一项的查询?

有时!

或者是否也应该在这些列上创建单独的索引(即 OrderID、CustomerID)以满足查询 1 和 2?

有时不是!

真正的答案是索引声明中列的顺序决定了索引中记录的顺序这一事实的细微差别。一些排序有助于一些查询,而另一些则没有。您可能需要再补充一个索引以涵盖 CustomerID、OrderID 的情况。


“由于我们想要的所有列都在索引中,我们不必查找实际的表”——所以索引可以用于读取目的,尽管不用于查找/查找目的?

当索引(它是表的一部分的副本)包含解析查询所需的所有信息时,不需要读取实际的表。索引“覆盖”查询。

于 2012-07-18T18:59:55.147 回答