这里我正在研究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和运营商的执行计划的成本相同? 我做错了什么或者这是预期的吗?
谢谢
答案 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
找到它,因为它是聚类键)。