【问题标题】:how does ordering by UUID work in PostgreSQL?UUID 排序如何在 PostgreSQL 中工作?
【发布时间】:2017-08-31 12:31:46
【问题描述】:

在 postgresql 上使用 uuid_generate_v1() 是否有任何顺序保证?

如果是,保证是每台机器,或者 UUID 是在哪台机器上生成的?由于 V1 UUID 是按时间戳 + MAC 地址,所以 Postgres 内部是否先按时间戳部分排序,然后按 MAC 地址排序?

我可以“排序”一个 UUID 类型列并期望它始终有效(似乎有效)吗?

我想在多台机器上生成 UUID(使用 postgresql uuid_generate_v1()),将它们复制到一个 Postgres 实例,然后按 UUID 列排序。它必须保证机器顺序,而不是所有机器的 UUID 的顺序。

【问题讨论】:

  • 时间戳可以从 UUID (v1) 中提取。你见过这个吗? stackoverflow.com/questions/37713131/…
  • 我看到了,但是在这个答案上没有建议功能的订购似乎也有效(使用普通的 ORDER BY 列)。不确定它是否与机器无关。
  • 没有统一的 UUID 排序(甚至字节布局)。但是,PostgreSQL 有一个特定于实现 UUID 排序,SQL Server 也是如此(这不保证是相同的;.NET 与 SQL Server 有不同的排序,即使两者都是 Microsoft 创建的...... )。因此 PostgreSQL 排序将是一致的。如果uuid_generate_v1 是 PgSQL 索引友好的和/或在 PgSQL 中基于“时间”的有序是一个特定的细节。
  • 无论如何,我找不到任何技术文档,但我会“假设”订单是“保证” PostgreSQL 中。更改顺序将是一个重大更改,并且可能依赖于 UUID 的二进制存储编码。如果出于任何原因,这些数据可能会在 PgSQL 的外部排序,那么 .. 不要依赖它 D:

标签: postgresql sql-order-by uuid postgresql-9.4


【解决方案1】:

UUID 不是为订购而设计的。

如果您想根据创建顺序选择记录,您应该使用时间戳date_creationauto-increment 列(不适用于您的特定情况),或者使用保证排序的算法创建自己的 ID;例如,连接时间戳 + UUID,或时间戳 + 自增。

您可以在数据库中创建function 以供以后选择。

【讨论】:

  • 时间戳的问题在于不能保证它们是唯一的。然而,时间戳+ uuid 的连接是独一无二的,可能是我的解决方案。问题是,连接时间戳 + uuid 是否比使用 order by timestamp, uuid 子句更快?
  • 整数时间戳将比字符串时间戳快很多。与使用两个专用列相比,连接会使您的索引变慢。
  • UUID 是 128 位数字(减去几位),并且可以是有序的 .. 取决于 1)它们是如何生成的(在这种情况下是 UUIDv1)和 2)它们是如何排序的。这个答案无法解决这两个问题。具体来说,数据库有一种特定的方式来对 UUID 进行排序(并且它会像任何排序一样快)。这种特定方式如何与通过 v1 生成的 UUID 保持一致?它可能不会(按时间)对齐,但这是相关细节。 SQL Server 中的newsquentialid() 是“UUID 不是为订购而设计的”的一个简单反例。
  • (在上面的评论中,我将“UUID”的范围扩展到了 5 种“官方定义”的生成类型 + 变体之外,这似乎是公平竞争..)
  • cassandra 中的timeuuid 已订购
【解决方案2】:

虽然绝不是一个明确的答案 - 即。 “是否在所有 PostgreSQL 安装中都定义了行为?”这个 SQL(用于 SQL Server)检查 GUID 中每个字节的顺序。可能需要对 PostgreSQL 进行一些调整。

生成这样的映射应该允许人们查看特定的 UUID 结构(明确定义的类型之一或其他)是否在 PostgreSQL 中“以特定方式排序”。

With UIDs As (--                           0 1 2 3  4 5  6 7  8 9  A B C D E F
            Select ID = 'F', UID = cast ('00000000-0000-0000-0000-000000000011' as uniqueidentifier)
    Union   Select ID = 'E', UID = cast ('00000000-0000-0000-0000-000000001100' as uniqueidentifier)
    Union   Select ID = 'D', UID = cast ('00000000-0000-0000-0000-000000110000' as uniqueidentifier)
    Union   Select ID = 'C', UID = cast ('00000000-0000-0000-0000-000011000000' as uniqueidentifier)
    Union   Select ID = 'B', UID = cast ('00000000-0000-0000-0000-001100000000' as uniqueidentifier)
    Union   Select ID = 'A', UID = cast ('00000000-0000-0000-0000-110000000000' as uniqueidentifier)
    Union   Select ID = '9', UID = cast ('00000000-0000-0000-0011-000000000000' as uniqueidentifier)
    Union   Select ID = '8', UID = cast ('00000000-0000-0000-1100-000000000000' as uniqueidentifier)
    Union   Select ID = '7', UID = cast ('00000000-0000-0011-0000-000000000000' as uniqueidentifier)
    Union   Select ID = '6', UID = cast ('00000000-0000-1100-0000-000000000000' as uniqueidentifier)
    Union   Select ID = '5', UID = cast ('00000000-0011-0000-0000-000000000000' as uniqueidentifier)
    Union   Select ID = '4', UID = cast ('00000000-1100-0000-0000-000000000000' as uniqueidentifier)
    Union   Select ID = '3', UID = cast ('00000011-0000-0000-0000-000000000000' as uniqueidentifier)
    Union   Select ID = '2', UID = cast ('00001100-0000-0000-0000-000000000000' as uniqueidentifier)
    Union   Select ID = '1', UID = cast ('00110000-0000-0000-0000-000000000000' as uniqueidentifier)
    Union   Select ID = '0', UID = cast ('11000000-0000-0000-0000-000000000000' as uniqueidentifier)
)
Select * From UIDs Order By UID desc

在 SQL Server(2014,and matches that in SQL Server 2005)中,降序的顺序是:

Position by highest-to-lowest value:

A B C D E F | 8 9 | 7 6 | 5 4 | 3 2 1 0

由于 SQL Server 的 newsequentialid 将这种排序用于索引友好的 GUID 生成,因此行为可能永远不会改变。 SQL Server 还必须在所有系统中保持这种行为以支持复制。因此,如果问题是关于 SQL Server,我肯定会说“in SQL Server 的 GUID 的顺序是一致的”,这绝对可以依赖 in SQL Server。

但是,此排序不同于 .NET 的 GUID 排序,如果 PostgreSQL 中的排序不同,我不会感到惊讶。 SQL Server 中的“翻转”差异是因为它遵循COM GUIDs 的“变体 2”(又名 little-endian)排序;甚至对于“变体 1”UUID 也是如此。 (然而,为什么这些组本身是从右到左排序的,这似乎更随意:更多的微软历史?)

有趣的问题仍然存在:在哪里/如何这个指定要在in PostgreSQL 中订购?如果没有很好的规范,实现是否仍然可以被视为行为公理?

还有see this question for more details about SQL Server's UUIDs;以及“为什么”存在这些差异的精彩细节。

【讨论】:

  • 对于任何来这里的人都想知道这个脚本的 Postgresql 输出,稍加修改,输出很好地排序 0 1 2 3 ... F。(PostgreSQL 9.5.14 on x86_64-pc -linux-gnu,由gcc编译(Ubuntu 5.4.0-6ubuntu1~16.04.10)5.4.0 20160609,64位)
猜你喜欢
  • 2016-10-09
  • 1970-01-01
  • 1970-01-01
  • 2011-07-05
  • 2012-01-05
  • 2012-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多