将guid和int用作表的唯一标识符有多普遍?

时间:2018-07-06 16:43:47

标签: sql sql-server database data-modeling

从dba的角度来看,我认为Guid通常是首选的唯一表行标识符。但是我正在一个项目中,开发人员和管理人员似乎想要一种通过int值引用事物的方法。我可以理解他们的观点,因为他们想要一种简单易行的方式来引用不同的实体。

我当时正在考虑为我的表使用一种模式,其中每个表都有一个表示PK列的int Id列,但随后它还将一个Guid列作为全局唯一标识符。使用这种类型的图案有多普遍?

2 个答案:

答案 0 :(得分:1)

在大多数情况下,您都希望对主键/外键使用INT或BIGINT。在大多数情况下,您都希望确保可以将表连接到其中,并可以轻松选择单个唯一行。在理论中,到处使用GUID也会使您到达那里,如果您是机器人,并且可以快速询问同事,“嘿,您可以检查ROW_ID FD229C39-2074-4B04-8A50-456402705C02” vs “嘿,您可以签出ROW_ID 523”。但是我们是人类。我认为,除了您的PK(应该应为INT或BIGINT)之外,没有其他理由仅是GUID列是一个很好的理由

按顺序订购PK也很不错,这似乎派上了用场。 GUID将不按顺序排列。但是,使用GUID的情况是您必须将此价值暴露给客户。您可能不希望他们知道他们是客户#6。但是,作为客户#B8D44820-DF75-44C9-8527-F6AC7D1D259B并不需要太大,如果他们必须打电话并标识自己的身份,但是对于编写针对的代码(例如,Web服务或某种API)可能会很好。 SQL是一门科学的艺术!

另外,您真的需要一个全局唯一的行吗?可能不会。如果您要设计一个系统,它消耗的电量可能超过INT的处理能力(例如,总的推文总数),那么请使用BIGINT。如果您可以用完所有的BIGINT,请哇。我想听听如何和希望订阅您的时事通讯。

我在写东西时问自己一个问题:“如果我错了,那么做另一种方法会有多困难?”。如果以后确实需要GUID,请添加它。如果您现在就把它放进去,只有一个人使用它,那么您永远都不会拿走它,必须对其进行维护……工作安全吗?不,不要这么想:)不要过度设计它。

答案 1 :(得分:0)

从DBA的角度来看,我不会说GUID通常是首选。它更大(16个字节,而不是int的4个字节,而bigint的是8个字节),并且随机变种会带来碎片,并且由于预期页寿命较低而导致大型表的IO增多。旋转介质和有限的RAM时尤其如此。

当实际需要GUID时,可以使用GUID值的顺序版本而不引入其他代理键来避免某些问题。值可以由SQL Server在列上使用NEWSEQUENTIALID()默认约束来分配,也可以在应用程序代码中生成,并为SQL Server正确地排列字节。下面是后一种技术的Windows C#示例。

using System;
using System.Runtime.InteropServices;

public class Example
{
    [DllImport("rpcrt4.dll", CharSet = CharSet.Auto)]
    public static extern int UuidCreateSequential(ref Guid guid);

    /// sequential guid for SQL Server
    public static Guid NewSequentialGuid()
    {
        const int S_OK = 0;
        const int RPC_S_UUID_LOCAL_ONLY = 1824;

        Guid oldGuid = Guid.Empty;

        int result = UuidCreateSequential(ref oldGuid);
        if (result != S_OK && result != RPC_S_UUID_LOCAL_ONLY)
        {
            throw new ExternalException("UuidCreateSequential call failed", result);
        }

        byte[] oldGuidBytes = oldGuid.ToByteArray();
        byte[] newGuidBytes = new byte[16];
        oldGuidBytes.CopyTo(newGuidBytes, 0);

        // swap low timestamp bytes (0-3)
        newGuidBytes[0] = oldGuidBytes[3];
        newGuidBytes[1] = oldGuidBytes[2];
        newGuidBytes[2] = oldGuidBytes[1];
        newGuidBytes[3] = oldGuidBytes[0];

        // swap middle timestamp bytes (4-5)
        newGuidBytes[4] = oldGuidBytes[5];
        newGuidBytes[5] = oldGuidBytes[4];

        // swap high timestamp bytes (6-7)
        newGuidBytes[6] = oldGuidBytes[7];
        newGuidBytes[7] = oldGuidBytes[6];

        //remaining 8 bytes are unchanged (8-15) 

        return new Guid(newGuidBytes);

    }

}