如何在多个SQL Server数据库之间共享单个序列?

How to share a single sequence between multiple SQL Server databases?

提问人:kermit 提问时间:6/28/2022 最后编辑:kermit 更新时间:6/29/2022 访问量:494

问:

我需要在两个不同的 SQL Server 数据库中的表之间共享一个 SQL Server 序列。此示例适用于两个现有表和在同一数据库上定义的序列:

USE DatabaseA ;
GO

CREATE SEQUENCE dbo.TransactionSequence START WITH 1 INCREMENT BY 1 ;
GO

ALTER TABLE Table1 ADD TransactionSequenceID int NOT NULL 
    CONSTRAINT DF_Table1_TransactionSequence DEFAULT (NEXT VALUE FOR dbo.TransactionSequence) ;
ALTER TABLE Table2 ADD TransactionSequenceID int NOT NULL 
    CONSTRAINT DF_Table2_TransactionSequence DEFAULT (NEXT VALUE FOR dbo.TransactionSequence) ;
GO

但是,对于其他数据库中的表,此命令失败:

USE DatabaseB ;
GO

ALTER TABLE Table3 ADD TransactionSequenceID int NOT NULL 
    CONSTRAINT DF_Table3_TransactionSequence DEFAULT (NEXT VALUE FOR DatabaseA.dbo.TransactionSequence) ;
GO

它失败,因为 SQL Server 不允许 DEFAULT 约束引用另一个数据库中的序列。
在此上下文中,序列不能通过同义词间接引用,并且不允许在函数或其他几个可能有用的构造中引用。不同数据库中的表是否可以共享一个序列?如果是这样,那如何?
NEXT VALUE FOR <sequence>

序列 SQL Server Multi-Database

评论

2赞 Thom A 6/28/2022
“不同数据库中的表是否可以共享一个序列?”只有通过在数据库中运行 ,然后对目标表使用 3 部分命名。在我看来,您想要共享 2 个不同数据库的事实表明存在设计缺陷;显然,这些对象应该位于同一个数据库中,而不是不同的数据库中。INSERTSEQUENCESEQUENCE
0赞 kermit 6/28/2022
@Larnu 谢谢你的评论。是的,这表示设计缺陷,但这些是遗留数据库,不幸的是,表无法移动。
0赞 Thom A 6/28/2022
然后,它们将需要单独的 s、@kermit .SEQUENCE
0赞 Jeroen Mostert 6/28/2022
它可以通过一个触发器来完成,因为它是免费调用的,尽管它并不漂亮 - 触发器的最大缺点是,如果模式发生变化,它们很容易中断(除了所有触发器的一般陷阱,例如确保它们不会无意中嵌套或生成输出)。INSTEAD OF INSERTTable3NEXT VALUE FOR DatabaseA.dbo.TransactionSequenceINSTEAD OF
0赞 kermit 6/30/2022
@JeroenMostert 您的评论可能与原始技术问题的答案一样接近,尽管我们都希望避免触发。谢谢你。顺便说一句,似乎基于Microsoft对序列使用的限制,也许序列是数据库范围的。任何违反该意图的尝试都将导致一个不太漂亮的解决方法。

答:

1赞 Ben Thul 6/29/2022 #1

我过去曾实现过类似的东西,根据您的需求/用例,它可能适合您。假设您需要一个在多个数据库中生成 WidgetID 值的序列。你可以这样做:

use [Widgets_001];
create sequence SQ_WidgetID
    as int
    start with 1
    minvalue 1
    maxvalue 1000000
    increment by 1;

use [Widgets_002];
create sequence SQ_WidgetID
    as int
    start with 1000001
    minvalue 1000001
    maxvalue 2000000
    increment by 1;

创建序列后,您可以在所需的任何默认约束中使用它们。

这里的想法是它们从不相交的范围内分配。由于序列是独立分配的,因此数据库甚至可以位于不同的服务器上。这确实伴随着需要监控范围耗尽的成本(例如,当Widget_001中的序列超过 950,000 时,可能是时候开始考虑分配新范围了)并注意重新设定序列的种子以从新范围分配(如果您有办法查看数据库中的所有序列并始终分配新范围以严格大于所有现有 s 的最大值)。minvaluemaxvalue

我个人抵制将任何意义归因于这些相应序列生成的值的诱惑。也就是说,很容易说“嗯......这就是 WidgetID 1234。因此,它在Widgets_001。这有其自身的问题。

评论

0赞 kermit 6/29/2022
非常感谢您提出的解决方案。不幸的是,我的要求是让表共享相同的序列。
0赞 Ben Thul 6/29/2022
为什么?该技术要求满足的业务需求是什么?
0赞 kermit 6/29/2022
我们需要知道记录插入到表中的顺序。
0赞 Ben Thul 6/29/2022
一般来说,将任何含义赋予这些类型的标识符是一个坏主意。它们的作用是为您提供一种方法,通过它唯一地标识数据库中的行,并相关地引用它。任何过去的事情最终都会导致违规行为。但是,即使有能够对记录进行排序的要求,最终也会有人问“它们是什么时候插入的?”或“它们之间的时差是什么?”。添加某种 DateCreated 列可以同时回答这两个问题(并且仍然提供您正在寻找的排序)。过你的生活,但是⚠️.
0赞 kermit 6/30/2022
谢谢!!!您的评论让我重新考虑使用 DateCreated 列。考虑到交易量,datetime 不起作用,这是我首先想到的。直到现在,我才想到使用具有亚微秒精度的 datetime2 数据类型列来对记录进行排序。我不能将您的回答标记为所述技术问题的解决方案,但您的评论非常有帮助!!