【问题标题】:What data type is recommended for ID columns?ID 列推荐使用什么数据类型?
【发布时间】:2010-10-30 05:55:28
【问题描述】:

我意识到这个问题很可能以前被问过,但我在 StackOverflow 上的问题中搜索了一些,但我并没有真正找到我的答案,所以这里是。如果您发现重复,请链接到它。

出于某种原因,我更喜欢使用Guids(MsSql 中的uniqueidentifier)作为我的主键字段,但我真的不知道为什么这样会更好。在我最近学习的许多教程中,使用了自动递增的int。我可以看到两者的优缺点:

  • Guid 始终具有相同的大小和长度,没有理由担心用完它们,而在用完之前可以拥有的记录数量是有限的适合int
  • int 是(至少在 C# 中)可空类型,在查询数据时打开几个快捷方式。
  • 而且int 更容易阅读。
  • 我敢打赌,您至少可以在这里想出更多的东西。

所以,正如标题所说的那样简单:推荐的数据库中 ID(主键)列的数据类型是什么?

编辑:收到几个简短的答案后,我还必须添加这个后续问题。没有它,您的答案既不具有说服力,也不具有教育意义... ;) 您为什么这么认为,以及使您选择它的其他选项的缺点是什么?强>

【问题讨论】:

  • 应该指出,GUID 和整数只是显示和生成字节序列的不同方式。在顺序生成整数的情况下,GUID 是“随机”生成的,并且其中有更多字节。这意味着您无需查看数据库的现有状态即可生成一个。在 C# 中,一切都可以用 ?就可以了。

标签: language-agnostic database-design types primary-key database-agnostic


【解决方案1】:

任何大小足以存储预期数据范围的整数类型。通常,对于具有大量行或更改的表,32 位整数被视为太小(正确或错误)。一个 64 位的 int 就足够了。许多数据库没有或不会使用该整数类型,但将使用具有指定比例和精度的 NUMBER 类型。 10-15 位数是相当常见的尺寸。

选择整数类型的原因有两个:

  1. 尺寸;和
  2. 速度。

整数的大小为:

  • 32 位:4 字节;
  • 64 位:8 字节;
  • 二进制编码的十进制:每个字节两位数加上符号、小数位数和/或精度的一个字节。

比较 GUID,它是 128 位或普通字符串,每个字符至少一个字节(在某些字符编码中更多)加上可能只有一个字节的开销(终止 null)或者在某些情况下可能更多。

排序整数是微不足道的,假设它们是唯一的并且范围足够小,实际上可以在 O(n) 时间内完成,而充其量是 O(n log n)。

同样重要的是,大多数数据库可以通过自动递增列和/或序列来生成唯一 ID。否则,在应用程序中保证唯一性实际上非常困难,而且往往会导致密钥膨胀。

加上自动生成的整数键通常是松散或绝对有序的(取决于数据库和配置),这是一个有用的品质。随机生成的 GUID 基本上是无序的,用处不大。

【讨论】:

    【解决方案2】:

    如果您使用 long,您可以每秒创建超过 1000 个,并且在 2900 万年内不会用完主键。

    其他人已经提到了使用整数类型而不是 UUID/GUID 的一些优点。一大优势是索引的速度和紧凑性。

    我最近参与的一个应用程序,我在其中进行数据库设计,我需要 UUID,但不想放弃使用 long 作为主键的优势,所以我有一个映射每个主键的“allIds”表在系统中键入 UUID。我的所有主键都是从一个序列生成的,因此它们在所有表中都是唯一的。

    【讨论】:

      【解决方案3】:

      多年来,流行的数据库允许更大的自动增量字段,因此问题要小得多。

      至于用什么,永远是一个选择。一个并不明显更好,它们具有不同的特性,并且在不同的场景中都很好。随着时间的推移,我已经使用了这两种模式,下一个我使用的模式我会同时考虑这两种模式。

      GUID 的优点:

      • 在计算机上应该是唯一的。
      • 随机的、令人难忘的粘性物意味着人们可能将其用于不透明标识符的预期目的。

      自动增量的优点:

      • 人类可以理解。
      • 顺序分配意味着您可以使用聚集索引并影响性能。
      • 适合数据分区。

      【讨论】:

        【解决方案4】:

        使用 GUID 键的一大缺点是很难手动执行“临时”查询。有时这样做非常有用:

        SELECT * FROM User where UserID=452245

        使用 GUID 键,这会变得非常烦人。

        我会推荐 64 位整数

        【讨论】:

        • 我想补充一点,GUID 不容易被人类阅读,所以如果我用我的交易 ID 致电客户支持,我宁愿提供一个数字而不是 GUID。只有机器应该读取 GUID。
        【解决方案5】:

        告诉我你认为哪些标准很重要。

        要求在表格中是唯一的。

        GUID 是全局概率唯一标识符。它也很大。如果您需要您的索引在 epsilon 内对宇宙中的所有其他数据库安装都是唯一的,那么这是一个不错的选择。否则,它会不必要地占用大量空间。

        自增数字是好的;它很小,而且在表中肯定是独一无二的。另一方面,它不能为您提供防止重复的保护;除了幻数之外,两个相同的条目很容易创建。

        使用与被描述实体相关的一些值可以避免这种情况,但您会遇到处理唯一性的问题。

        【讨论】:

          【解决方案6】:

          如果数据库是分布式的,您可以从其他数据库中获取记录,则主键需要在一个表中是唯一的在所有数据库中。 GUID 解决了这个问题,尽管以空间为代价。自动增量和命名空间的组合将是一个很好的权衡。

          如果数据库可以为带有“前缀”的自动增量提供内置支持,那就太好了。因此,在一个数据库中,我得到 X1、X2、X3 ... 等 ID,而在另一个数据库中,它可能是 Y1、Y2、Y3 ... 等等。

          【讨论】:

          • 您认为您的 X1 和 Y2 将是什么数据类型?字符串?在这种情况下,您最好使用 GUID...
          【解决方案7】:

          我问了一个类似的问题,其中有一些可能会有所帮助的答案。复制似乎是使用 GUID 的最大优势。

          Reasons not to use an auto-incrementing number for a primary key

          【讨论】:

            【解决方案8】:

            听从 Cletus 的建议, 另外需要注意的是,这在很大程度上取决于您的存储方式。永远不要使用 GUID。 GUID 有很多缺点,只有一两个优点。

            【讨论】:

              【解决方案9】:

              我从不喜欢整数和递增标识符。当您想要跨不同表(两个表相同 ID)或跨不同数据库复制数据时,就会出现问题。 Guid 作为字符串代表很大,当您在 Web 应用程序 url 中包含 id 时也会出现问题。所以我决定使用一个短字符串版本的 Guid,它在数据库中就像 varchar(16)。请参见下面的代码(方法 WebHash()):

              public static class IdentifyGenerator
              {
                  private static object objLock = new object();
              
                  private static char[] sybmols = {
                                       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                                       'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
                                       'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
                                       'u', 'v', 'w', 'x', 'y', 'z',
                                   };
              
                  /// <summary>
                  /// Creates a new Unique Identity HashCode (length 16 chars)
                  /// </summary>
                  /// <returns></returns>
                  public static string WebHash(Guid fromGuid = default(Guid))
                  {
                      lock (objLock)
                          return RandomString(16, (fromGuid != default(Guid) ? fromGuid.ToByteArray() : null));
                  }
              
                  public static string RandomString(int length, byte[] customBytes = null)
                  {
                      Stack<byte> bytes = customBytes != null ? new Stack<byte>(customBytes) : new Stack<byte>();
                      string output = string.Empty;
              
                      for (int i = 0; i < length; i++)
                      {
                          if (bytes.Count == 0)
                              bytes = new Stack<byte>(Guid.NewGuid().ToByteArray());
                          byte pop = bytes.Pop();
                          output += sybmols[pop % sybmols.Length];
                      }
                      return output;
                  }
              }
              

              唯一的缺点是在 SQL 中创建新行时。所以你必须创建一个类似的sql函数。

              很高兴在我的地址中收到任何批评。

              【讨论】:

                猜你喜欢
                • 2015-03-08
                • 2016-01-24
                • 1970-01-01
                • 1970-01-01
                • 2018-05-13
                • 1970-01-01
                • 2022-08-09
                • 2021-04-17
                • 2011-07-17
                相关资源
                最近更新 更多