Sql server 何时使用覆盖索引、复合索引和唯一列索引

Sql server 何时使用覆盖索引、复合索引和唯一列索引,sql-server,database-design,indexing,rdbms,Sql Server,Database Design,Indexing,Rdbms,假设我在SQL Server 2008中有下表: ProfileID int //identity; index: unique, primary key, clustered ClientID int RegionID int ProfileName nvarchar(50) 第2列和第3列通过外部关系链接到各自的表 假设我最常见的问题是: SELECT ProfileID, ProfileName FROM Profiles WHERE Client

假设我在SQL Server 2008中有下表:

ProfileID   int          //identity; index: unique, primary key, clustered
ClientID    int
RegionID    int
ProfileName nvarchar(50)
第2列和第3列通过外部关系链接到各自的表

假设我最常见的问题是:

SELECT ProfileID, ProfileName
FROM   Profiles
WHERE  ClientID = ? AND RegionID = ?
ORDER  BY ProfileName
什么索引系统最适合

如果我在(ProfileID,ProfileName)上放置了一个覆盖索引,那么这将终止默认聚集索引,因为覆盖索引必须是非聚集索引,但至少满足查询的返回部分

如果我将主键保持原样,并独立索引ClientID和RegionID,这将提供3个必须由RDBMS维护的索引,加上表扫描仍然需要返回ProfileName,因为它没有被覆盖。这似乎很重

这是一个简单的案例,说明索引计划的复杂性。

对于此查询:

SELECT  ProfileID, ProfileName
FROM    Profiles
WHERE   ClientID = ? AND RegionID = ?
ORDER BY
        ProfileName
CREATE INDEX ix_profiles_region_client_name__id ON (RegionID, ClientID, ProfileName) INCLUDE (ProfileID)
您应该创建以下索引:

CREATE INDEX ix_profiles_region_client_name ON (RegionID, ClientID, ProfileName)
(RegionID,ClientID)
的单个值内,记录在
ProfileName
上进行排序,这样记录将被排序,无需额外排序

由于
ProfileID
是一个
主键集群
,它隐式地包含在每个索引记录中,因此不需要在索引定义中明确指定它

如果它不是聚集键,则需要将其添加到索引中,以覆盖此查询:

SELECT  ProfileID, ProfileName
FROM    Profiles
WHERE   ClientID = ? AND RegionID = ?
ORDER BY
        ProfileName
CREATE INDEX ix_profiles_region_client_name__id ON (RegionID, ClientID, ProfileName) INCLUDE (ProfileID)
对于此查询:

SELECT  ProfileID, ProfileName
FROM    Profiles
WHERE   ClientID = ? AND RegionID = ?
ORDER BY
        ProfileName
CREATE INDEX ix_profiles_region_client_name__id ON (RegionID, ClientID, ProfileName) INCLUDE (ProfileID)
您应该创建以下索引:

CREATE INDEX ix_profiles_region_client_name ON (RegionID, ClientID, ProfileName)
(RegionID,ClientID)
的单个值内,记录在
ProfileName
上进行排序,这样记录将被排序,无需额外排序

由于
ProfileID
是一个
主键集群
,它隐式地包含在每个索引记录中,因此不需要在索引定义中明确指定它

如果它不是聚集键,则需要将其添加到索引中,以覆盖此查询:

SELECT  ProfileID, ProfileName
FROM    Profiles
WHERE   ClientID = ? AND RegionID = ?
ORDER BY
        ProfileName
CREATE INDEX ix_profiles_region_client_name__id ON (RegionID, ClientID, ProfileName) INCLUDE (ProfileID)

@我的朋友,你回来了。我猜你的意思是“…也保留主索引”?不仅仅是这一个索引?我有两个问题:1)我认为(ClientID,RegionID…)会更好,因为ClientID是最独特的列(好吧,我在我的问题中没有提到这一点,是的)。我认为顺序从最独特到最不独特。第二个问题是为什么ProfileName在索引中,而不是作为一个包含的列,而我们不是专门查询它?@Ianc:对于这个查询,它并不重要,因为搜索总是在整个元组
(ClientID,RegionID)
上执行。但是,如果需要单独搜索
ClientID
(或与
RegionID
以外的列组合搜索),则可以交换顺序
ProfileName
在索引中,因为它在
orderby
子句中使用。包含的列不按索引排序,因此如果将
ProfileName
作为非键列包含,则查询需要排序。@谢谢。最后一个问题,如果你不介意的话。如果我需要经常搜索ClientID或RegionID,您提供的索引是否仍然是最佳的?@IanC:两个单独的索引最好:
(ClientID,RegionID)
RegionID
@Quassnoi我的朋友,您回来了。我猜你的意思是“…也保留主索引”?不仅仅是这一个索引?我有两个问题:1)我认为(ClientID,RegionID…)会更好,因为ClientID是最独特的列(好吧,我在我的问题中没有提到这一点,是的)。我认为顺序从最独特到最不独特。第二个问题是为什么ProfileName在索引中,而不是作为一个包含的列,而我们不是专门查询它?@Ianc:对于这个查询,它并不重要,因为搜索总是在整个元组
(ClientID,RegionID)
上执行。但是,如果需要单独搜索
ClientID
(或与
RegionID
以外的列组合搜索),则可以交换顺序
ProfileName
在索引中,因为它在
orderby
子句中使用。包含的列不按索引排序,因此如果将
ProfileName
作为非键列包含,则查询需要排序。@谢谢。最后一个问题,如果你不介意的话。如果我需要经常搜索ClientID或RegionID,您提供的索引是否仍然是最佳的?@IanC:两个单独的索引最好:
(ClientID,RegionID)
RegionID