-1

我有一个有 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

提前致谢。

4

2 回答 2

0

快速回答,的,删除主键(此外,用单个标识列替换当前的多列主键)然后在 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 需要能够从 NCI 返回 CI 以获取其余列。为此,CI 的主键与列子集一起存储在 NCI 中。所以NCI实际上就像一个(Month_ID,CI主键)的两列表。

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

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

于 2015-03-06T21:23:40.217 回答
0

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)
于 2015-03-06T19:30:32.100 回答