这个复合索引会帮助所有这些查询吗?

时间:2012-07-18 18:47:24

标签: sql-server-2008 tsql indexing

假设我有下表:

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?

3 个答案:

答案 0 :(得分:6)

此索引对第二个查询没有帮助,因为无法首先搜索索引中最左侧的列。

想一下电话簿。首先,尝试找到姓史密斯的所有人。容易,对吗?现在,尝试找到名字为John的所有人。电话簿中“索引”的工作方式是LastName,FirstName。当你试图找到所有的约翰时,首先按照LastName排序它们根本没有用 - 你仍然需要浏览整本电话簿,因为会有一个John Anderson和一个John Zolti以及介于两者之间的所有内容。

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

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

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

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

答案 1 :(得分: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中查询 - 包括实际执行计划,然后运行查询。您将看到使用哪些索引的图形表示,是否执行搜索或扫描等。

答案 2 :(得分: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案例。


  

“因为我们想要的所有列都在索引中,所以我们不必查找实际的表” - 所以索引可以用于阅读目的,虽然不用于搜索/查找目的?

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