事实表上覆盖索引的用处

Posted

技术标签:

【中文标题】事实表上覆盖索引的用处【英文标题】:Usefulness of a covering index on a fact table 【发布时间】:2012-06-15 18:33:01 【问题描述】:

考虑如下形式的事实表:

CREATE TABLE Fact1
(
    Dim1 int NOT NULL,
    Dim2 int NOT NULL,
    Dim3 int NOT NULL,
    Data1 int NOT NULL,
    Data2 int NOT NULL
    ...
)

Fact1 在每个维度上都有一个单列索引。 Dim1 被假定为时间维度,粒度小到小时范围(例如,2011 年 3 月 12 日下午 2 点到 6 点之间)。在 Dim1 中包含 Dim2Dim3 作为覆盖列是否有用?或者同样在其中任何一个上?

更一般地说,将其他维度表的 FK 列作为给定维度的索引上的覆盖列包含在内是否有用?

注意:对于事实表,我们假设不需要唯一标识给定的事实。因此,缺少主键或代理键。 (Dim1, Dim2, Dim3) 始终是唯一的元组来保证唯一性。

【问题讨论】:

覆盖索引用于仅从索引中获取数据而不转到表本身的情况。您多久查询一次此表中仅在 Dim2 和 Dim3 上的数据,反之,当您查询 Dim1 并且还需要来自 Dim2 和 Dim3 的数据时? @NWest:真的没有“最常见的查询”。有几个要么单独在任何一个维度上,要么在它们的任意组合上。 等等,Dim1 是一个范围的时间吗?为什么?那么Dim2Dim3 是什么?实际上,您是否需要索引将基于分析和查询模式。而且您拥有一个唯一键 - 它是 (Dim1, Dim2, Dim3) - 您可能希望将此作为主键(尽管我不是 DBA,所以。 ..) @X-Zero 通常在仓库环境中,完整性由 ETL 流程而非 DBMS 强制执行。 @X-Zero: Dim1 是一个时间范围,因为被建模的数量是一段时间内的东西。考虑比这更精细的东西是没有意义的,因为任何比几个小时更精细的东西都是无用的。 @NWest 也记录了完整性部分。 【参考方案1】:

我将尝试回答更一般的问题 - “将其他维度表 FK 列作为给定维度的索引上的覆盖列包含在内是否有用?”

是的。如果您有大量执行 COUNT() 等操作的查询,其中覆盖索引允许您扫描较小的数据集,那么添加这些其他维度可能很有价值。

SELECT Dim1, Dim2, count(*)
from Fact1
group by Dim1, Dim2

使用仅 Dim1 或仅 Dim2 上的索引,您最终必须执行 FTS 才能进行此计数。 这可能完全没问题。完全扫描并不总是坏事。但是,如果你想加快这些类型的查询(比如事实表非常宽),那么在 Dim1 上添加 B 树索引,Dim2 将允许 DBMS 运行到索引来计数,而不必去表去计数。请注意,它仍然会对索引进行全盘扫描,这可能只比全表扫描快一点。

总的来说,我怀疑您是否会看到这么多的性能提升,因为无论如何您仍在扫描索引的所有行,除非索引明显小于表,否则您可能不会得到很大改进。

由于它是一个事实表,唯一有助于在维度上覆盖索引的查询是仅在查询维度本身时。任何使用事实的东西都需要进行索引扫描,然后在表中查找实际数据。

我可能只是在 dims 上为使用键(和连接)的查询构建 B-tree 索引,然后在系统运行一段时间并识别常见查询时根据需要添加其他索引。

我能想到的另一种情况是,当您的查询专注于特定维度组合,而您只需要那些特定行时,诸如此类的“覆盖”索引可能有助于加快查询速度。

p>
SELECT Dim1, Dim2, Data1, Data2
  FROM Fact1 
 WHERE Dim1 = @A and Dim2 = @B;

如果您在 Dim1, Dim2 而不仅仅是 Dim1 上有一个 b-tree 索引,您可能会看到非常轻微的性能提升,因为您扫描索引以查找 WHERE 子句中的所有项目,然后得到您的事实数据。

【讨论】:

谢谢。这或多或少是我想要的。有一些细节,但我想知道您为什么可以或为什么不为这种特定模式类型使用覆盖索引的一般原因。 添加了另一种情况,当此“覆盖”索引可能有助于加快查询速度时(尽管在这种情况下它并不能真正充当“覆盖”索引。 请注意,我的思想已经发展,不一定会推荐金博尔风格的方法来处理任何事情。但是,正如您从大多数数据仓库人员那里听到的那样,我将保持原样。

以上是关于事实表上覆盖索引的用处的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL索引和复制技术

浅聊 MySQL索引覆盖

回表与覆盖索引,索引下推

mysql覆盖索引和联合索引的区别

「Mysql索引原理(七)」覆盖索引

在SQL中使用 WHERE字句中使用,= < >等的表达式,是否在一个有创建索引的表上查询,索引会失效?