为非唯一聚集索引创建一个可见的唯一符列

Hug*_*une 3 sql-server sql-server-2014 unique-constraint computed-column

我有一个事件表,聚集索引是创建日期/时间。

通常情况下,在同一毫秒内永远不会发生两个事件,但会发生异常事件,因此该列不一定是唯一的。

我想添加一个 uniquifier 列,即在给定时间内插入的第一个行为 0,第二个为 1,依此类推:

TIME                    UNIQUIFIER,     TEXT
2018-01-01 01:23:45.678,   0,           "aaa"
2018-01-01 02:00:00.000,   0,           "bbb"
2018-01-01 02:00:00.000,   1,           "ccc"
2018-01-01 02:00:00.000,   2,           "ddd"
2018-01-01 03:45:67.890,   0,           "eee"
Run Code Online (Sandbox Code Playgroud)

我知道当我创建聚集索引时,MS Sql Server 会自动创建这样一个列。但是该列是隐藏的。

我想要一个可见的 uniquifier,它的行为就像这个隐藏的一样,所以我可以在外键关系中使用它。

也就是说,当...

  • 另一个表需要引用现有事件,
  • 而我只知道那件事发生的时间,
  • 而我只关心同时发生的第一个事件,

...我可以Time:2018-01-01 02:00:00 / Uniquifier:0用作外键,知道该行存在,而无需在第一个表中查找事件。

我可以使用自动递增的标识列来使键唯一,但这意味着我无法在不知道标识列的情况下引用事件。

例如,如果我想在单独的 1-n 表中创建事件和一堆额外的事件信息,我必须首先创建事件,然后查找其标识列,然后才创建相关信息,使用它身份栏。我试图避免往返。

是否有可能在 SQL Server 中使用自动值填充这样一个可见的列,与隐藏的 uniquifier 列相同?

还是在插入行时必须手动计算这样的列?

Pau*_*ite 7

是否有可能在 SQL Server 中使用自动值填充这样一个可见的列,与隐藏的 uniquifier 列相同?

不,没有内置功能可以做到这一点。

还是在插入行时必须手动计算这样的列?

当插入/更新/删除行时,您可以考虑使用INSTEAD OFAFTER触发器来维护同一时间组的正确的类似唯一标识符的行为。

这可能需要仔细考虑才能在高并发下正确运行,但最好尽可能靠近数据(即服务器端、数据库中,而不是客户端)。编写良好的触发器(具有支持性索引)将引入最少的开销。

或者,使索引唯一并实现重试逻辑。由于预期似乎很少发生碰撞,因此这很可能是可以接受的。


Dan*_*man 5

将标识列添加到 CI 键将避免与内部唯一标识符值类似的重复。请务必选择像 bigint 这样的数据类型以避免溢出。

如果源数据包含比您当前存储的时间精度更高的时间精度,请考虑使用它datetime2(7)来减少冲突并提供更高的精度。

当您只关心给定时间内的第一个事件时,请使用ROW_NUMBER() OVER(PARTITION BY time ORDER BY time, identity_column)并选择第 1 行。