【问题标题】:Should I create index on a SQL table column used frequently in WHERE select clause?我应该在 WHERE 选择子句中经常使用的 SQL 表列上创建索引吗?
【发布时间】:2013-11-17 20:58:07
【问题描述】:

所以我想知道我是否应该将非聚集索引添加到 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% 的记录

【问题讨论】:

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


    【解决方案1】:

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

    您通常应该向用作外键的列添加非聚集索引,前提是该列具有合理数量的多样性,我将通过一个示例进行解释。

    这同样适用于 where 子句、order by 等中使用的列。

    例子

    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 管理工作室中显示的执行计划尝试查询。如果查询优化器认为索引会产生积极影响,它将为您建议索引。

    希望有帮助!

    【讨论】:

    • 感谢您的详尽回答!这是一个包含 100 多个城市的百万多条记录表。所以 select 会返回表中 0.1% 到 5% 的记录。
    • 酷,听起来好像该列上的索引是个好主意,假设这个查询(或其他在 where 子句中使用 city 列的查询)足够频繁。如果它是一个非常频繁的查询,甚至可能值得在索引中包含其他列。例如:CREATE NONCLUSTERED INDEX IX_1 ON Customers(City) INCLUDE (Id, FirstName, LastName) 这就是所谓的覆盖索引(最快,因为查询完全被索引覆盖,无需查找其他列)。请注意,这会增加它在磁盘上的大小,+ 使 INSERT/UPDATES 慢一些。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2011-11-25
      • 1970-01-01
      • 1970-01-01
      • 2011-02-01
      • 1970-01-01
      • 2010-09-21
      • 2013-08-04
      • 2011-08-24
      • 1970-01-01
      相关资源
      最近更新 更多