47

首先,我知道这个问题,并且建议(使用 GUID)不适用于我的情况。

我想要简单的 UID,以便我的用户可以轻松地通过电话传达此信息:

您好,我的订单 1584 有问题

您好,我的订单 4daz33-d4gerz384867-8234878-14 有问题

我希望它们是唯一的(数据库范围内的),因为我有几种不同类型的“对象”……有订单 ID、交货 ID 和计费 ID,因为它们之间没有一对一的关系,我无法猜测 ID 指的是哪种对象。

使用数据库范围的唯一 ID,我可以立即分辨出我的客户所指的对象。我的用户只需在搜索工具中输入一个 ID,我就可以为他节省额外的点击以进一步细化正在查找的内容。

我目前的想法是使用具有不同种子 1、2、3 等的标识列,增量值为 100。

这提出了几个问题:

  • 如果我最终得到超过 100 个对象类型怎么办?授予我可以使用 1000 或 10000,但是不能很好扩展的东西“闻起来”

  • 种子是否有可能“丢失”(在复制、数据库问题等期间?)

  • 更一般地说,还有其他我应该注意的问题吗?

  • 是否可以使用非整数(我目前使用 bigints)作为标识列,以便我可以在 ID 前面加上代表对象类型的东西?(例如 varchar 列)

  • 使用仅包含标识列和对象类型的“主表”是否是个好主意,这样我可以在需要新想法时在其中插入一行。我觉得这可能有点矫枉过正,而且我担心它会使我所有的插入请求变得复杂。另外,如果不查看数据库,我将无法确定对象类型

  • 还有其他聪明的方法来解决我的问题吗?

4

11 回答 11

56

为什么不在所有表上都使用身份,而在任何时候将其呈现给用户时,只需为该类型添加一个字符?例如,O1234 是订单,D123213 是交货,等等?这样你就不必设计一些疯狂的计划......

于 2009-04-06T13:50:10.977 回答
13

在用户界面处理——在向用户报告时在 ID 号上添加一个(或多个)前缀字母。所以 o472 是订单,b531 是账单,以此类推。在通过电话输入“数字”时,人们很容易混合字母和数字,并且比直接数字更准确。

于 2009-04-06T13:53:55.007 回答
12

您可以使用自动增量列来生成唯一 ID。然后有一个计算列,该列采用该列的值并在其前面加上一个反映实体类型的固定标识符,例如 OR1542 和 DL1542,分别表示订单 #1542 和交付 #1542。您的前缀可以根据需要进行扩展,并且可以安排格式以帮助区分具有相同自动增量值的项目,例如 OR011542 和 DL021542,前缀为 OR01 和 DL02。

于 2009-04-06T13:51:28.150 回答
3

我将通过定义一个通用根表来实现。因为没有更好的名字,所以叫它实体。Entity 表上至少应该有一个 Identity 列。您还可以包括所有对象中常见的其他字段,甚至包括告诉您此行是订单的元数据。

您的每个实际 Order、Delivery... 表都会有一个指向 Entity 表的 FK 引用。这将为您提供一个唯一的 ID 列

在我看来,使用种子是一个坏主意,而且可能会导致问题。

编辑

你已经提到的一些问题。我还认为跟踪并确保您正确设置所有新实体是一件很痛苦的事情。想象一个开发人员在两年后更新系统。

在我写完这个答案之后,我想到了更多关于你为什么这样做的想法,我得出了与马特相同的结论。

于 2009-04-06T13:44:59.833 回答
3

MS 的有意编程项目有一个 GUID-to-word 系统,可以从随机 ID 中给出可发音的名称

于 2009-04-16T02:44:03.977 回答
3

为什么不是 bigint 的简单 Base36 表示? http://en.wikipedia.org/wiki/Base_36

于 2009-05-01T20:57:31.947 回答
1

我们在一个项目中遇到了类似的问题。我们通过首先创建一个只有一行的简单表来解决它:将 BIGINT 设置为自动增量标识。我们创建了一个存储过程,它在该表中插入一个新行,使用默认值并在事务内部。然后它将 存储SCOPE_IDENTITY在一个变量中,回滚事务,然后返回存储的SCOPE_IDENTITY

这为我们提供了数据库内的唯一 ID,而无需填写表格。

如果您想知道 ID 指的是哪种对象,我会丢失事务回滚并将对象类型存储在 ID 旁边。这样就可以找出 Id 所指的对象类型只有一个选择(或内部连接)。

于 2009-04-16T18:15:20.307 回答
1

我为此使用了高/低算法。我在网上找不到这个的描述。必须写博客。

在我的数据库中,我有一个带有计数器字段的 ID 表。这是高的部分。在我的应用程序中,我有一个从 0 到 99 的计数器。这是较低的部分。生成的密钥为 100 * high + low。

要获得密钥,我执行以下操作

initially high = -1
initially low = 0

method GetNewKey()
begin
  if high = -1 then
    high = GetNewHighFromDatabase

  newkey = 100 * high + low.
  Inc low
  If low = 100 then
    low = 0
    high = -1

  return newKey
end

真正的代码使用锁等更复杂,但这是一般要点。

有很多方法可以从数据库中获取高价值,包括自动 inc 键、生成器等。最好的方法取决于您使用的数据库。

该算法提供了简单的密钥,同时避免了每次查找新密钥的大部分数据库命中。在测试中,我发现它与 guid 具有相似的性能,并且比每次都检索 auto inc 密钥的性能要好得多。

于 2009-04-17T00:14:27.073 回答
0

UniqueObject您可以使用您的身份和子类型字段创建一个主表。子表(订单、用户等)将具有 UniqueObject 的 FK。INSTEAD OF INSERT触发器应将疼痛降至最低。

于 2009-04-06T13:46:25.900 回答
0

也许是 itemType-year-week-orderNumberThisWeek 变体?

o2009-22-93402

这样的标识符可以由几个数据库列值组成,并由软件简单地格式化为标识符的形式。

于 2009-04-16T09:51:24.700 回答
0

我在一个项目中遇到了类似的情况。

我的解决方案:默认情况下,用户只能看到 GUID 的前 7 个字符。

它是足够随机的,碰撞极不可能发生(2.68 亿分之一),而且它对于说话和打字都很有效。

当然,在内部,我使用的是整个 GUID。

于 2009-06-16T20:10:04.227 回答