【问题标题】:Which index is better non-clustered vs clustered in this case?在这种情况下,哪个索引是非聚集索引比聚集索引更好?
【发布时间】:2015-05-08 11:42:24
【问题描述】:

我有一个表,其中有 4 列 (region_id, product_id, cate_id, month_id) 作为主键。 此主键是默认创建的,因此为 PK 创建了聚集索引。 此表包含超过 1000 万行。

如果我删除现有的 pk 并创建一个具有非聚集索引类型的新 pk,对于以下查询,它是否比聚集索引更好?

select region_id, product_id, cate_id, month_id, a, b, c 
from fact_a
where month_id > 100

提前致谢。

【问题讨论】:

  • 如果这是一个运行很多的查询,为什么不呢?非聚集索引用于提高聚集索引未覆盖的性能。
  • 一张表上不能有多个聚集索引。你能详细说明你在这里的实际意思吗?
  • 我已经更新了我的问题,很抱歉造成混乱。
  • 这些列是什么数据类型?通常,聚集索引应尽可能窄、唯一且静态。拥有四列很少是理想的......
  • 问这种一次性问题不是一个好方法。你在这里学到的很少。只需阅读(简短的)索引教程,这个问题就会很容易回答。

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


【解决方案1】:

month_id 上的简单非聚集索引肯定会提高该查询的平均性能(假设大多数行的month_id 小于100,因此where 子句排除了大部分行)。但是,如果您正在专门为该查询创建索引(或在 where 子句中使用 month_id 和 a、b、c、month_id 或 select 中的子集的任何查询),您会变得更好通过在索引中包含所选值来产生结果,如下所示:

CREATE INDEX index_fact_a_month_id ON fact_a (month_id) INCLUDE (a,b,c)

【讨论】:

    【解决方案2】:

    快速回答,,删除主键(此外,用单个标识列替换当前的多列主键)然后在 Month_ID 上创建 NCI 会更好/更快/更高效。

    聚集索引 - 它是数据。它包含表中每一行的每一列。 CI 只能有一个,因为表数据只需要存在一次。每行都有一个键...

    主键 - 它是在聚集索引中识别行的键。

    非聚集索引 - 它充当聚集索引中行的列子集的表。

    保持简单,非聚集索引包含的数据比聚集索引少,并且它以某种方式对数据进行排序 (Month_id ASC),这使得对它的查询比对它的查询更有效CI(A、B、C、Month_ID)。 SQL Server 无法“深入”CI 主键或行数据并说:“嘿,我正在按 Month_ID 进行过滤,所以我将直接进入该列。”根据聚集索引的性质,SQL Server 会“读取”所有 CI 行(索引扫描)、每一列、每一个数据字节。非常低效和浪费,因为您的 WHERE 子句将过滤掉很多这些行。

    非聚集索引仅包含列的子集,因此它更有效,因为它可以说:“嘿,我正在按 Month_ID 过滤,我只包含 Month_ID,aannnd Month_ID 是按升序排列的,所以我可以直接跳到我想要的行!” (索引搜索)。效率更高,因为 SQL Server 只会“读取”您要返回的行。

    再进阶一点,由于非聚集索引只有 Month_ID,但您要查询聚集索引中的所有列,SQL Server 需要能够返回 CI从 NCI 获取其余列。为此,CI 的主键与列子集一起存储在 NCI 中。所以 NCI 真的很像(Month_ID,CI 主键)的两列表。

    如果您的主键很糟糕,您的 NCI 也会很糟糕,因此效率会降低(更多的磁盘读取、更多的缓冲池消耗、坏的数据库内容)。

    免责声明:在某些特定情况下,您可能希望每列都成为聚集索引键/pk。我不觉得这适用于这里,但这是可能的。如果您有一个频繁使用的查询,该查询在 where 子句或连接中引用表的每一列,那么覆盖聚集索引可能会有所帮助。

    【讨论】:

      猜你喜欢
      • 2014-01-09
      • 2013-08-07
      • 1970-01-01
      • 2021-01-14
      • 2021-09-07
      • 2014-07-28
      • 2020-08-04
      • 2011-04-05
      相关资源
      最近更新 更多