【问题标题】:Will replacing the primary key clustered index with another index cause issues?用另一个索引替换主键聚集索引会导致问题吗?
【发布时间】:2014-02-22 19:49:31
【问题描述】:

使用 SQL Server 2008/2012,我目前有两个表,如下所示:

tblAccount (accountID BIGINT, accountActive BIT)

tblSite (siteID BIGINT, accountID BIGINT, siteActive BIT)

目前,tblAccount 上的accountID 是主键和聚集索引。

tblSite上的siteID是主键和聚集索引

我的大部分查询将采用以下形式:

SELECT <fields>
FROM <some table> X
INNER JOIN tblSite s ON s.siteID = X.siteID
INNER JOIN tblAccount a ON a.accountID = s.accountID
WHERE 
   x.<field> = SOMETHING  
   AND a.accountActive = 1 
   AND s.siteActive = 1

我的理解是,为了优化这些查询,最好在tblAccounttblSite 上放置新的聚集索引。

类似:

CREATE CLUSTERED INDEX ON tblAccount (accountActive,accountID) WITH .....

CREATE CLUSTERED INDEX ON tblSite (siteActive,siteID) WITH .....

显然,为此,我必须删除两个表的 PK 聚集索引。

这是否有可能导致进一步的问题?正如我假设的那样(使用帐户表),该表现在针对

进行了优化
SELECT * 
FROM tblAccount 
WHERE accountID = X 
  AND accountActive = Y

就这样吧

SELECT * 
FROM tblAccount 
WHERE accountID = X

将高度未优化?

我在 account 表上创建了另外两个索引,我不知道这些会对上面的索引和查询产生多大的影响:

CREATE UNIQUE NONCLUSTERED INDEX idx_account_session 
    ON tblAccount (accountSessionKey,accountActive,accountAffirmed,accountLastAction)     
    INCLUDE (accountID) 
    WITH (STATISTICS_NORECOMPUTE=OFF,SORT_IN_TEMPDB=ON,FILLFACTOR=80)

CREATE NONCLUSTERED INDEX idx_account_login 
    ON tblAccount (accountEmail,accountPassword,accountAffirmed,accountActive) 
    INCLUDE (accountID,accountSaltHash) 
    WITH (STATISTICS_NORECOMPUTE=OFF,SORT_IN_TEMPDB=ON,FILLFACTOR=80)

我已将这些用于优化身份验证存储过程。

非常感谢您的帮助。

【问题讨论】:

  • 更改聚集索引将改变您的表的工作方式,目前accountID 是唯一的,但如果您在 accountID 和 Active 上创建聚集索引,您最终可能会得到相同 accountID 的 2 条记录(一个活跃,一个不活跃)。索引位字段的好处在很大程度上取决于您的数据分布。您的帐户中有多少是活跃的?
  • 如果您在(AccountID, AccountActive) 上有一个索引,那么这个索引也可以单独用于针对AccountID 的查询——那里没有性能损失。但是 clustering index 是决定表的物理布局的索引,并且会自动包含在 all 其他非聚集索引中 - 我会确保它尽可能小尽可能,并且唯一 - 否则 SQL Server 将向您的索引添加“隐藏的”唯一性 - 这不是一件好事!
  • @GarethD - 大多数帐户和网站都将处于活动状态,应该如何调整索引?
  • @marc_s - 所以在创建索引时,例如CREATE UNIQUE NONCLUSTERED INDEX idx_account_session ON tblAccount (accountSessionKey,accountActive,accountAffirmed,accountLastAction) INCLUDE (accountID) WITH (STATISTICS_NORECOMPUTE=OFF,SORT_IN_TEMPDB=ON,FILLFACTOR=80) 是 INCLUDE (accountID)?
  • 如果大多数帐户都处于活动状态,我个人不会费心为其编制索引,read this answer 了解有关索引位字段的更多信息。

标签: sql sql-server join indexing


【解决方案1】:

更改聚集索引将改变您的表的工作方式,目前accountID 是唯一的,但如果您在 accountID 和 Active 上创建聚集索引,您最终可能会得到相同 accountID 的 2 条记录(一条处于活动状态,一条不处于活动状态) .因此,为了更改集群键并保持 AccountID 的唯一性,您还需要添加唯一约束(或唯一索引)。

如果您大部分时间都在查询活动帐户/网站,并且您觉得性能有问题,我会选择indexed view,并保持您在 accountID 上的聚集索引不变。

CREATE VIEW dbo.ActiveAccount
WITH SCHEMABINDING
AS
    SELECT  AccountID, <Columns>
    FROM    dbo.tblAccount 
    WHERE   ActiveAccount = 1;
GO
CREATE UNIQUE CLUSTERED INDEX UQ_ActiveAccount_AccountID 
    ON dbo.ActiveAccount (AccountID);
GO

还有一个类似的 Site 索引视图,因此您的查询变为:

SELECT  <columns>
FROM    ActiveAccount A (NOEXPAND)
        INNER JOIN ActiveSite s (NOEXPAND)
            ON a.accountID = s.accountID;

但是,当您想要所有帐户/站点而不仅仅是活动帐户/站点时,您可以查询主表而不是索引视图。

请注意,尽管维护此索引视图的成本可能超过您从中选择所获得的好处,如评论中所述,它取决于您的数据的基数和频率您只需要查询活动帐户/网站。

【讨论】:

  • 哇,要考虑的东西太多了……就在我认为我对 SQL Server 有了很好的理解时,更多的东西会自己发现。我看到有人尝试像我一样进行内部连接,而 Stack Overflow 上的答案是更改聚集索引。那么什么时候更改聚集索引是个好主意呢?什么时候使用索引视图是个好主意?
  • 简而言之,如果不完全考虑到任何查询的上下文之外,集群键应该主要是,请记住集群索引是您的表数据。主要因素应该是表数据本身。 This article 提供了一些关于选择正确集群密钥的指南。一旦选择(正确),就不应该真的需要改变它(除非需求改变)。对于查询优化,我总是使用非聚集索引或索引视图进行优化,而不是更改表本身。
猜你喜欢
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-05
相关资源
最近更新 更多