14

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

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

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

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

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

4

9 回答 9

16

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

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

  1. 尺寸; 和
  2. 速度。

整数的大小为:

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

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

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

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

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

于 2009-05-31T14:15:22.640 回答
7

多年来,流行的数据库允许更大的自动增量字段,所以这不是一个问题。

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

GUID 的优点:

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

自动增量的优点:

  • 人类可以理解。
  • 顺序分配意味着您可以使用聚集索引并影响性能。
  • 适用于数据分区。
于 2009-05-31T14:24:31.890 回答
6

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

SELECT * FROM 用户,其中用户 ID=452245

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

我会推荐 64 位整数

于 2009-05-31T14:25:46.210 回答
2

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

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

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

于 2009-05-31T14:15:38.040 回答
2

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

需要的是在表中是唯一的

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

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

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

于 2009-05-31T14:26:12.947 回答
0

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

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

于 2009-05-31T14:47:38.770 回答
0

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

不使用自动递增数字作为主键的原因

于 2009-05-31T14:49:47.160 回答
0

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

于 2009-06-21T18:53:00.863 回答
0

我从不喜欢整数和递增的标识符。当您想要跨不同表(两个表相同 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 函数。

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

于 2019-05-06T11:40:46.997 回答