假设我有下表:
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?
答案 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案例。
“因为我们想要的所有列都在索引中,所以我们不必查找实际的表” - 所以索引可以用于阅读目的,虽然不用于搜索/查找目的?
当索引(表的一部分的副本)包含解析查询所需的所有信息时,不需要读取实际表。索引“覆盖”了查询。