我应该在WHERE select子句中频繁使用的SQL表列上创建索引吗?

时间:2013-11-06 14:50:40

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

所以我想知道是否应该将非聚集索引添加到SQL 2008 R2表中的非唯一值列。 简化示例:

 SELECT Id, FirstName, LastName, City
 FROM Customers
 WHERE City = 'MyCity'

我的理解是主键[Id]应该是聚集索引。

非聚集索引可以添加到非唯一列[City]吗? 这会改善性能还是我不应该费心。

感谢。

我当时想把聚集索引作为:

 CREATE UNIQUE CLUSTERED INDEX IDX_Customers_City 
  ON Customers (City, Id);

或非群集,假设该表上已有聚簇索引。

  CREATE NONCLUSTERED INDEX IX_Customers_City 
  ON Customers (City, Id);

实际上我正在处理数百万条记录表。 Select语句返回记录的0.1%到5%

2 个答案:

答案 0 :(得分:2)

通常是 - 您通常会在主键上创建聚簇索引。 例外情况是,您从不基于主键进行查找,在这种情况下,将聚簇索引放在另一列上可能更相关。

您通常应该将非聚集索引添加到用作外键的列,前提是该列上存在相当多的多样性,我将通过示例进行解释。

这同样适用于where子句中使用的列,等等。

实施例

CREATE TABLE Gender (
 GenderId INT NOT NULL PRIMARY KEY CLUSTERED
 Value NVARCHAR(50) NOT NULL)

INSERT Gender(Id, Value) VALUES (1, 'Male'), (2, 'Female')

CREATE TABLE Person (
  PersonId INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED,
  Name NVARCHAR(50) NOT NULL,
  GenderId INT NOT NULL FOREIGN KEY REFERENCES Gender(GenderId)
)

CREATE TABLE Order (
  OrderId INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED,
  OrderDate DATETIME NOT NULL DEFAULT GETDATE(),
  OrderTotal DECIMAL(14,2) NOT NULL,
  OrderedByPersonId INT NOT NULL FOREIGN KEY REFERENCES Person(PersonId)
)

在这个简单的表格集中,最好在Order表的OrderedByPersonId列上放置一个索引,因为您很可能想要检索给定人员的所有订单,并且很可能有很多的多样性。 通过大量的多样性(或选择性),我的意思是,如果你说1000个客户,每个客户每个可能只有1或2个订单,所以使用给定的OrderedByPersonId查找订单表中的所有值将导致只返回该表中总记录的一小部分。

相比之下,在Person表中的GenderId列上放置一个索引并没有多大意义,因为它的多样性非常低。查询优化器不会使用这样的索引,而INSERT / UPDATE语句会稍微慢一些,因为需要维护索引。

现在回到你的例子 - 答案必须是“它取决于”。如果您的数据库中有数百个城市,那么是,将该列编入索引可能是个好主意 如果你只有3或4个城市,那么不 - 不要打扰。作为指导,我可能会说如果列的选择性为0.9或更高(即,在列中选择单个值的where子句将导致仅返回10%或更少的行)索引可能会有所帮助,但这是绝不是一个坚强而快速的人物!

即使该列具有非常高的选择性/多样性,如果查询只是偶尔进行查询,也可能无法对其进行索引。

最容易做的事情之一就是尝试查询SQL管理工作室中显示的执行计划。如果查询优化器认为它们会产生积极影响,它会为您建议索引。

希望有所帮助!

答案 1 :(得分:1)

如果您经常使用查询,或者如果您在线应用程序中定期按城市排序,特别是如果您的表密集或行数较大,则添加索引是有意义的。索引太多会降低插入和更新的速度。只有在表中包含重要数据时,才能理解对实际值的评估。