在给定场景中,事实表中是不是需要/推荐 Id 列

Posted

技术标签:

【中文标题】在给定场景中,事实表中是不是需要/推荐 Id 列【英文标题】:Is Id column required / recommended in fact table in the given scenario在给定场景中,事实表中是否需要/推荐 Id 列 【发布时间】:2014-05-02 05:47:48 【问题描述】:

我在 SQL Server 2012 中使用具有以下结构的事实表:

CREATE TABLE [dbo].[factTable] (
    [Id]            BIGINT      IDENTITY (1, 1) NOT NULL,
    [Date]          DATE        NOT NULL,
    [MinuteNumber]  SMALLINT    NOT NULL,
    [CityId]        INT         NOT NULL, /* Foreign key to dimCity */
    [Value]         DECIMAL(12, 4)  NULL
)

我在Date 列上有一个聚集索引,填充因子为 100。插入此表的数据几乎总是按DateMinuteNumber 的升序排列。

    我想知道 - 在给定的场景中是否需要使用 Id 列?它有任何性能影响吗?或者我可以安全地消除它吗?

    我还想知道在Date 列上是否有聚集索引是否足够(会有许多记录具有相同的日期,甚至相同的日期和相同的分钟数)还是有一个聚集索引更好索引组合多列;两种方法对性能和存储的影响是什么?

我是新手,我们将不胜感激。

【问题讨论】:

在这种情况下,如果您的日期列具有相似的数据,则您创建了一个非唯一聚集索引。我宁愿建议在 ID 列上使用聚集索引,然后您可能可以在 date+city-id 上创建一个唯一的非聚集索引 通常在数据仓库中,将事实表链接到日期和城市等维度表更有意义。这使 DimDate 表能够保存诸如年、月、星期几、季度之类的值等,并允许更大的灵活性和易于查询。维度表的键值通常只是表示为整数的日期,例如今天是 20140502。这方面有很多文章和一些好书,例如 Kimball 的 microsoft datawarehouse toolkit。 【参考方案1】:

聚集索引必须是唯一的,因此如果您决定使用 DATE,您将需要另一个列,它们一起始终是唯一的。聚集索引还可以物理控制数据的顺序,因此键应该是始终按升序排列的键。再说一次,你的 DATE 似乎有一些东西,你做对了。

但是,最好知道您的表将包含多少数据,以及您计划使用多少个非聚集索引?由于每个非聚集索引叶记录都包含一个指向聚集索引的指针,所以一般来说,您不希望聚集索引比它必须的大。

基本上,将简单的自动整数数字作为聚集索引的键列的优点是它在存储方面非常有效,它总是按顺序递增,并且与其他对象和用例也具有良好的协同作用。

这里的用户marc_s发布了another site (link)的链接,我想你一定要看看。

但总而言之,在大多数情况下,安全的赌注是保持简单,只需在基本的 int / bigint 标识列上放置一个聚集索引,然后使用非聚集索引来优化对表中特定列的搜索。在大多数情况下,这已经足够好了。无需使事情复杂化,并在已经运行得足够快的查询上寻找 5% 的改进。所以,问题是,您是否有任何理由期望标准解决方案不适用于您的情况?例如,大量 数据(这里说的是 bigint 规模行,例如超过数十亿)、其他性能影响(与同一数据库中的其他表的复杂条件连接)或其他类似的事情?

【讨论】:

感谢您的回复。我已经有大约 4300 万条记录,我预计在不久的将来会有两倍或更多。我现在明白了唯一的聚集键被非聚集索引使用,所以在标识上使用索引是一个更好的主意。我的大部分查询将主要使用日期字段和城市。那么您是否建议在 Date 和 CityId 上添加非聚集索引?我的插入不频繁,因此可以接受慢速插入;但是我已经有几分钟时间将数据从转换表合并到这个表中。 @user3446562:聚集索引列是 SQL Server 数据库中最冗余的东西 - 所以它们越小越好。此外,一个好的聚集索引必须是唯一的 - 单独的 DATE 通常不能提供这一点。我几乎总是会选择ID INT IDENTITY(或BIGINT)——在绝大多数情况下,它是最安全、最简单、最高效的。 -1 代表“聚集索引必须唯一”的神话。它必须是窄的、上升的和稳定的,但如果需要,SQL Server 会添加一个唯一性。 CI 可以非常有效地支持范围查询。 PK 必须是唯一的,但不必是集群的。话虽如此,我还是会在这里填写身份列。 我假设合并是指实际合并,意味着比较源和目标之间的记录并在适用的情况下更新/删除/插入?在这种情况下,查看实际的合并 SQL 会很有帮助。现在,由于我们不知道您的全部情况,我在这里做一些猜测,但我假设将 Id 更改为聚集索引,然后在 Date 和 CityId 上创建一个非聚集索引(如果您确实同时使用 BOTH) ,并检查合并查询中的过滤器以对其进行优化,就足够了。 @marc_s 好的,语义 :) 让我换个说法。声明 CI 的列中的值不必是唯一的,句号。添加唯一性只是一个实现细节,不需要关心。这里真正重要的是,选择 CI 不应该是为了独特性,而应该是为了其他一些品质。【参考方案2】:

在您的情况下,我可能会在标识列上创建一个非聚集主键,以便更轻松地进行 FK 关系管理和提高性能。

聚集键将位于date 列上,以允许更快的范围查询。 date 列还满足聚集索引的三个基本要求:窄(使非聚集索引更小)、稳定(因为 CI 列的更改也意味着重新洗牌 NC 索引,这是要避免的)而且它还在增加(为了避免 bad 页面拆分,那些不在表格末尾的页面拆分)。

WRT 非唯一聚集索引,如果它不是唯一的,SQL Server 会添加一个唯一标识符数据。

【讨论】:

谢谢院长。如果我不打算从其他任何地方引用此表上的数据(即没有外键),我是否需要此事实表中的标识列?

以上是关于在给定场景中,事实表中是不是需要/推荐 Id 列的主要内容,如果未能解决你的问题,请参考以下文章

事实表中的事实值或度量是啥意思?

Flink Async I/O

从维度表设置事实表中的 ID

查询以获取亚马逊红移中给定日期到 48 小时内的数据

如果维度/事实表中的数据未正确加载,我需要执行哪些步骤来清理数据

使用父行 ID 设计事实表