【问题标题】:Database-wide unique-yet-simple identifiers in SQL ServerSQL Server 中数据库范围内唯一但简单的标识符
【发布时间】:2023-03-25 08:10:01
【问题描述】:

首先,我知道this question,建议(使用 GUID)不适用于我的情况。

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

您好,我的订单有问题 第1584章

相对于

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

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

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

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

这提出了几个问题:

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

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

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

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

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

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

【问题讨论】:

  • 我在向用户公开 IDENTITY 值时遇到了问题。在 2000 年,对于像我这样的软件工程师来说是重要的一年,我加入了一家公司,并被分配了 2000 号员工。我一直在与人员对话,类似于帕丁顿熊和地铁检票员之间的对话:“.. .我问,'你叫什么名字?而不是“你想去哪里?”……”

标签: sql sql-server database database-design identity


【解决方案1】:

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

【讨论】:

  • 就像我们常说的“Jinx”。我的版本几乎相同,除了我建议小写字母以避免“O”和“D”被读为“0”,“B”被读为“8”等。在这种情况下,我的小写字母要好得多(除了代表“l”)。
  • 我会建议相同的解决方案,但对每个实体使用一个代码,如 Josh somethinkg 所述,例如 001-1584,其中 order 为 001
  • 或更正式地说,订单是001-
【解决方案2】:

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

【讨论】:

  • 这是有道理的。您不会收到“我对对象 #435 有疑问”。所以“订单#435”转换为“O435”的ID/PK,“付款#435”转换为“P435”的ID/PK。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

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

    编辑

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

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

    【讨论】:

    • @josh : 你能详细说明你想到的问题吗?
    • 这基本上就是实现它们的数据库中的“OID”。当您只需要以地理为中心的数据库时,它们很好。如今,UUID 或 COMB GUID 更好。它们可以在本地生成,并在以地理为中心的服务器上使用简单的键/值设备进行比较。更好的是,您可以在每个国家/地区放置一个这样的服务器,并为该键/值服务器附加/后置两个字符的国家/地区名称,即 550e8400-e29b-41d4-a716-446655440000fr。如果你想让它更小,让它 base64+fr。
    【解决方案5】:

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

    【讨论】:

    • 你有这方面的例子吗?听起来很有趣。
    【解决方案6】:

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

    【讨论】:

    • 一定要去掉元音!
    • @Jonathan:我看不出这将如何解决问题;你能详细说明一下吗?
    【解决方案7】:

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

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

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

    【讨论】:

      【解决方案8】:

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

      在我的数据库中,我有一个带有计数器字段的 ID 表。这是高的部分。在我的应用程序中,我有一个从 0 到 99 的计数器。这是低位部分。生成的key是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 密钥的性能要好得多。

      【讨论】:

        【解决方案9】:

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

        【讨论】:

          【解决方案10】:

          可能是 itemType-year-week-orderNumberThisWeek 的变体?

          o2009-22-93402
          

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

          【讨论】:

            【解决方案11】:

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

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

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-01-26
              • 1970-01-01
              • 2011-03-26
              • 1970-01-01
              • 2015-11-23
              • 1970-01-01
              • 1970-01-01
              • 2017-07-15
              相关资源
              最近更新 更多