动态顺序标识列和条件约束?

时间:2018-09-28 02:09:36

标签: sql sql-server database database-design

希望你们可以帮助我集思广益,为我在工作中遇到的障碍提供一些思路。我会尽力在这里提供尽可能多的信息。

1)ProductSerialEnum-这是一个表,其中包含各种产品类型的序列号枚举。它的作用是定义产品可以拥有的序列号的范围。新类型将不断涌现,因此这是当前示例

ProductTypeId   SerialPrefix SerialStartRange     SerialEndRange
--------------- ------------ -------------------- --------------------
1               2            2000000000           2999999999
2               1            1000000000           1999999999
3               4            4000000000           4999999999
4               3            3000000000           3999999999
5               501          5010000000           5019999999
6               500          5000000000           5009999999
7               601          6010000000           6019999999
8               600          6000000000           6009999999
...             ...          ...                  ...

2)预期的结果

产品-这是产品属性表,我将简化为重要的内容。

这是我希望这张桌子看起来像的样子,但是我遇到了满足我所有成功条件的问题。

ProductId   ProductTypeId   SerialNumber
----------- --------------- ------------
1           2               100000000
2           2               100000001
3           2               100000002
4           2               100000003
5           2               100000004
6           2               100000005
7           2               100000006
8           2               100000007
9           4               300000000
10          4               300000001
11          4               300000002

依此类推...

我的问题是,填充“产品”表以使其像我上面发布的示例一样工作的最佳方法是什么。

当必须插入产品时,会提供一个ProductTypeId,插入时我会生成一个序列号,该序列号由SerialEnum表中的范围定义。

这些序列号必须按每种Enum类型的顺序插入,如您所期望的示例所示。它们是顺序的绝对关键,我们不能刻录任何序列号,因为这些范围是我们分配的范围。

我最初的想法是生成一个插入SP,该SP带有我的关键ProductType的Product信息,然后保存该产品的序列范围的最大序列号,然后简单地插入下一个值。

但是,数据库接收到大量并发流量,因此我最担心的是序列号冲突以及由于并发或锁定问题而跳过大范围的块。

我曾经考虑过其他选项,例如可能对表进行分区以及弄乱IDENTITY列和范围,但是随着产品类型范围的扩大,我经常无法跟上不断运行分区方案的步伐产品类型会改变。

总而言之,表中插入的每个产品都必须根据ProductType表中定义的序列号范围生成唯一且连续的序列号,而不会浪费序列号或由于并发问题而导致错误。

如果任何人有一些经验或想法,如果您能将他们从我身上反弹,我将非常感谢!

2 个答案:

答案 0 :(得分:0)

  

我们不能刻录任何序列号

  

但是数据库收到大量并发流量

是互斥的。如果您不能丢掉它们,那么您需要对您的事务进行序列化以使其100%提交并分配一个数字,然后再进行下一步。如果您使用快速,序列或标识,那么您可能会有空白,因为将从序列缓存中分配ID。失败或回滚将导致间隙。

如果允许,您可以始终在事件后批量分配序列号。这将需要在主键上具有快速,序列或标识列,并插入一个空白序列号。您会定期扫描数据库中的空白SN,并根据代理ID的顺序(而非值)使用ROW_NUMBER()分配它们。

这将保证不存在任何空白,但是有时并非所有产品都有序列号。

答案 1 :(得分:0)

我假设每个范围都足以防止在应用程序的预期寿命内发生过渡。另外,您可以通过在创建过程中尽可能长地推迟序列号的生成来减少“已刻录”序列号的数量,但是我想不出一种有效的方法来完全消除它。您很可能会有一些差距。

以代码形式,作为Web服务或对您的应用程序最方便的方式进行操作。在ProductSerialEnum中添加一列,其名称类似于NextAvailableValue,其开头为SerialStartRange中的值。启动时将在此表中读取代码。

您的API定义了一个条目,在该条目中分配了下一个可用的序列号,其副本递增,过程返回。当然,新的NextAvalableValue需要保留下来,但是可以随时生成。这样,该I / O不会减慢该进程的响应时间。

您当然可以通过查询数据库来执行此操作,但是内存处理过程可以在执行一次查询时返回数千个序列号。

有许多有效的方法可以保持数据库中的值定期更新并保持更改的内存中值。这些取决于您的平台。

严格来说,这不是面向数据库的解决方案,但肯定比这种解决方案更快,并且可能更健壮。