Sequential Guid相对于标准Guid的性能提升有哪些?

mas*_*ini 65 database guid primary-key

当在数据库中用作主键时,有人曾测量过Sequential Guid与Standard Guid的性能吗?

mas*_*ini 105

GUID与顺序GUID



一种典型的模式是使用Guid作为表的PK,但是,正如其他讨论中所提到的(参见GUID/UUID数据库密钥的优缺点),存在一些性能问题.

这是典型的Guid序列

f3818d69-2552-40b7-a403-01a6db4552f7
7ce31615-fafb-42c4-b317-40d21a6a3c60
94732fc7-768e-4cf2-9107-f0953f6795a5


此类数据的问题是:<
-

  • 广泛的价值分布
  • 几乎是随机的
  • 索引使用非常非常非常糟糕
  • 很多叶子移动
  • 几乎每个PK都需要至少在非聚集索引上
  • Oracle和SQL Server都会出现问题



可能的解决方案是使用Sequential Guid,生成如下:

cc6466f7-1066-11dd-acb6-005056c00008
cc6466f8-1066-11dd-acb6-005056c00008
cc6466f9-1066-11dd-acb6-005056c00008


如何从C#代码生成它们:

[DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(out Guid guid);

public static Guid SequentialGuid()
{
    const int RPC_S_OK = 0;
    Guid g;
    if (UuidCreateSequential(out g) != RPC_S_OK)
        return Guid.NewGuid();
    else
        return g;
}
Run Code Online (Sandbox Code Playgroud)


优点

  • 更好地使用索引
  • 允许使用群集密钥(在NLB方案中进行验证)
  • 减少磁盘使用量
  • 以最低成本增加20-25%的性能



现实生活测量: 场景:

  • Guid在SQL Server上存储为UniqueIdentifier类型
  • Guid在Oracle上存储为CHAR(36)
  • 很多插入操作,在单个事务中一起批处理
  • 根据表格,从1到100个插件
  • 一些表> 1000万行



实验室测试 - SQL Server

VS2008测试,10个并发用户,没有思考时间,基准测试过程中有600个批量插入表用于叶表
Standard Guid
Avg.处理时间:10.5
平均 请求第二名:54.6
平均 RESP.时间:0.26

顺序Guid
平均 处理时间:4.6
平均 请求第二名:87.1
平均 RESP.时间:0.12

对Oracle的结果(对不起,用于测试的不同工具)1.327.613在带有Guid PK

Standard Guid的桌子上插入,0.02秒.每次插入的经过时间,2.861秒.CPU时间总数31.049秒 已

过时顺序指导,0.00秒.每次插入的经过时间,1.142秒.CPU时间,总计3.667秒.已过去

DB文件顺序读取等待时间从6.4百万等待事件传递62.415秒到120万等待事件持续11.063秒.

重要的是要看到所有顺序guid都可以被猜到,所以如果安全性是一个问题,仍然使用标准guid,使用它们并不是一个好主意.
简而言之......如果你使用Guid作为PK,每次它们不会从UI传回和传递时使用顺序guid,它们将加快操作并且不需要花费任何代价来实现.


Dan*_*Dan 52

我可能在这里遗漏了一些东西(如果我愿意,可以随意纠正我),但我可以看到使用顺序GUID/UUID作为主键的好处很少.

使用的GUID或UUID的在自动递增的整数是:

  • 它们可以在任何地方创建而无需联系数据库
  • 它们是在您的应用程序中完全唯一的标识符(在UUID的情况下,通用唯一)
  • 给定一个标识符,没有办法猜测在暴力之外的下一个或前一个(甚至任何其他有效标识符) - 强制一个巨大的密钥空间.

不幸的是,使用你的建议,你会失去所有这些东西.

所以,是的.你已经使GUID变得更好了.但是在这个过程中,你几乎抛弃了几乎所有使用它们的理由.

如果您真的想提高性能,请使用标准的自动增量整数主键.这提供了您所描述的所有好处(以及更多),而几乎在所有方面都优于"顺序指导".

这很可能会被贬低为遗忘,因为它没有专门回答你的问题(这显然是精心制作的,所以你可以立即自己回答),但我觉得这是一个更重要的一点.

  • 顺序UUID不保证全局排序.它们仍然是普遍独特的,但它们也是本地顺序的.这意味着在不同主机/进程/线程上生成的ID(取决于顺序方案)随机交错,但在同一环境中生成的ID将被排序. (15认同)
  • COMB GUID是有序的,并且插入/读取速度非常快,并且提供与标识列相当的速度.身份列的所有perc,但您不需要使用任何带有GUID的疯狂复制策略.你做的标识栏.优势GUID. (2认同)

Ber*_*her 21

正如massimogentilini已经说过的,使用UuidCreateSequential时可以提高性能(在代码中生成guid时).但似乎缺少一个事实:SQL Server(至少Microsoft SQL 2005/2008)使用相同的功能,但是:Guids的比较/排序在.NET和SQL Server上有所不同,这仍然会导致更多的IO,因为guid不会被正确订购.为了生成为sql server(订购)正确订购的guid,您必须执行以下操作(请参阅比较详细信息):

[System.Runtime.InteropServices.DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(byte[] buffer);

static Guid NewSequentialGuid() {

    byte[] raw = new byte[16];
    if (UuidCreateSequential(raw) != 0)
        throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());

    byte[] fix = new byte[16];

    // reverse 0..3
    fix[0x0] = raw[0x3];
    fix[0x1] = raw[0x2];
    fix[0x2] = raw[0x1];
    fix[0x3] = raw[0x0];

    // reverse 4 & 5
    fix[0x4] = raw[0x5];
    fix[0x5] = raw[0x4];

    // reverse 6 & 7
    fix[0x6] = raw[0x7];
    fix[0x7] = raw[0x6];

    // all other are unchanged
    fix[0x8] = raw[0x8];
    fix[0x9] = raw[0x9];
    fix[0xA] = raw[0xA];
    fix[0xB] = raw[0xB];
    fix[0xC] = raw[0xC];
    fix[0xD] = raw[0xD];
    fix[0xE] = raw[0xE];
    fix[0xF] = raw[0xF];

    return new Guid(fix);
}
Run Code Online (Sandbox Code Playgroud)

此链接此链接.

  • 有关其他信息,请参阅http://stackoverflow.com/questions/1752004/sequential-guid-generator-c和http://developmenttips.blogspot.com/2008/03/generate-sequential-guids-for-sql.html这个主题. (4认同)

小智 5

见这篇文章:(http://www.shirmanov.com/2010/05/generate-newsequentialid-compatible.html

即使 MSSql 使用这个相同的函数来生成 NewSequencialIds ( UuidCreateSequential(out Guid guid) ),MSSQL 反转了第 3 和第 4 字节模式,这不会给你在你的代码中使用这个函数时得到的相同结果。Shirmanov 展示了如何获得与 MSSQL 完全相同的结果。


Ale*_*man 5

我使用实体框架弄乱了 Guid(集群和非集群)、Sequential Guid 和 int(身份/自动增量)之间的区别。与具有同一性的 int 相比,Sequential Guid 的速度快得惊人。Sequential Guid 的结果和代码请参见此处