我应该使用哪种非聚集索引?

时间:2010-05-23 00:56:44

标签: sql-server-2008 indexing non-clustered-index

这里我正在研究SQL Server Management Studio上的非聚簇索引。

我创建了一个包含超过100万条记录的表。该表有一个主键。

CREATE TABLE [dbo].[Customers](
    [CustomerId] [int] IDENTITY(1,1) NOT NULL,
    [CustomerName] [varchar](100) NOT NULL,
    [Deleted] [bit] NOT NULL,
    [Active] [bit] NOT NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
(
    [CustomerId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,     ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

这是我将用于查看正在执行的执行计划的查询:

SELECT CustomerName FROM Customers

好吧,执行此命令时没有额外的非聚集索引,它会导致执行计划显示:

I/O cost = 3.45646
Operator cost = 4.57715

现在我试图看看是否可以提高性能,所以我为这个表创建了一个非聚集索引:

1)首个非聚集索引

CREATE NONCLUSTERED INDEX [IX_CustomerID_CustomerName] ON [dbo].[Customers] 
(
    [CustomerId] ASC,
    [CustomerName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON,
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

再次对Customers表执行select,执行计划显示:

I/O cost = 2.79942
Operator cost = 3.92001

似乎更好。现在我删除了这个刚创建的非聚集索引,以便创建一个新索引:

2)第一个非聚集索引

CREATE NONCLUSTERED INDEX [IX_CustomerIDIncludeCustomerName] ON [dbo].[Customers] 
(
    [CustomerId] ASC
)
INCLUDE ( [CustomerName]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF,  
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF,   
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

使用这个新的非聚集索引,我再次执行了select语句,执行计划显示了相同的结果:

I/O cost = 2.79942
Operator cost = 3.92001

那么,我应该使用哪个非聚集索引? 为什么I / O和运营商的执行计划的成本相同? 我做错了什么或者这是预期的吗?

谢谢

3 个答案:

答案 0 :(得分:2)

这是因为“CustomerName”在第二个索引中为INCLUDE - (请参阅this关于INLCUDEd列。)

基本上,BOTH索引的工作方式与您完全相同 - 它们是覆盖索引,第一个索引列与WHERE子句不匹配。

这意味着两种情况下的查询都将扫描索引,但不会触及表格。

我希望该索引能够更好地执行特定查询的 将仅是CustomerName的索引。

答案 1 :(得分:1)

在通过使用WHERE过滤结果,使用ORDER排序结果或将结果连接到索引列上的另一个表来使用索引之前,您不会注意到有或没有索引的差异。

尝试执行不带索引的查询:

SELECT *
FROM Customers
WHERE CustomerName = 'Marcus Adams'

然后在CustomerName列上添加一个索引,然后重试。

您还需要表中数据库系统实际使用索引的足够行,并且您会注意到扫描行和使用索引之间的区别。

答案 2 :(得分:0)

你的两个非聚集索引都没有多大意义,真的。

重点在于:聚集索引的列(在您的情况下为CustomerId)已包含在您拥有的每个非聚集索引的每个条目中。如果找到条目,那么聚类列就是用于实际数据查找的内容。因此,将其添加到非聚集索引通常是多余的,只是浪费空间。

问题更多:如何选择要显示的行?哪些列会显示在WHERE子句中?

如果你在这里找到一个模式(例如你总是选择City),那么非聚集索引将是

CREATE NONCLUSTERED INDEX [IX_Customer_City] ON [dbo].[Customers] 
(
    [City] ASC
)
INCLUDE ( [CustomerName]) 

这样,您就可以为SQL Server提供一种方法来轻松查找与给定城市匹配的行,并且包括您希望返回的列(CustomerName)允许SQL Server直接从中获取必要的信息。索引页面(使其成为所谓的covering index - 它涵盖了您的查询,例如返回所需的所有信息) - 您不需要进行“书签查找”,例如从实际数据页中获取整个Customer数据行(通过非聚集索引中的CustomerId找到它,因为它是聚类键)。