UUID做主键,好还是不好?这是个问题

完成Delphi中的UUID生成模块后, 不小心看到了这篇内容. 这些观点让我进行了深入思考. 遗憾的是目前所有引用均来自他人的转录, 无法确定最初的来源渠道.
对于我来说比较熟悉的数据库系统就是MySQL。大多数采用MySQL的人都倾向于使用Autoincrement ID来做主键设计。这也是可以理解的因为它利用自增ID实现主键具有很高的效率和便捷性。然而大约有99%左右的人都会采用这种自增主键设计这也是一种常见且可靠的选择。至于剩下的约1%则可能会考虑其他方案以确保数据的安全性和管理上的灵活性一种常见的选择则是自己开发的一个KeyGenerator工具另一种常见的选择则是UUID(Unique Identifier)系统。
据传,在Oracle圈子中若有人使用自增型ID作为主键,则常被视为不恰当的做法;而最自然的选择则是采用UUID作为主键。我对Oracle的具体情况并不清楚,并非专业人士 有关这些传闻的具体准确性我无从得知。
让我们来了解什么是UUID?简而言之,UUID指的是一个随机生成的一个数字序列,在同一时间段内能够唯一标识每一个设备。
在UUID算法中可能会用到网卡MAC地址、IP地址、主机名以及进程ID等多种信息以确保其唯一性和不可重复性。
如果你的MySQL版本不太老的话,键入 SELECT UUID(); 输出的就是UUID,如下:
mysql> select uuid();
+--------------------------------------+
|uuid()|
+--------------------------------------+
|54b4c01f-dce0-102a-a4e0-462c07a00c5e|
+--------------------------------------+
代码解读
大家对UUID已经有了一种直观的理解。接下来我们来分析一下UUID的主要优势和不足。
优点:
能够保证独立性,程序可以在不同的数据库间迁移,效果不受影响。
确保生成的ID既具有表外键独立性又具备库级独立性这一点在你计划将数据库进行切分时至关重要。
在oracle做数据迁移的时候不会因为表的sequence不连续而出现问题
缺点:
比较占地方,和INT类型相比,存储一个UUID要花费更多的空间。
使用UUID后,URL显得冗长,不够友好。
下面针对上述UUID的缺点说说我的看法:
- 空间占用问题对我来说并不是特别关注。
- 目前最廉价的资源反而是硬盘存储容量。
- 暂且忽略这一缺陷不会造成什么问题。
- 数据在索引过程中,其效率会随着存储量的增长而下降。
- 关于采用UUID后导致URL不够友好这一观点。
- 需要注意的是,在这种情况下选择INT可能更加合适。
- 事实上,在这种情况下选择INT可能更加合适是一个自然的选择。
- 另外需要注意的一点是:当一个电子商务网站按照INT友好的URL设计时,
- 其订单URL通常会形如:/order.php/id/123
- 我想强调的是:这种设计虽然友好但过于宽容可能会带来安全隐患。
- 例如,在某个清晨下单时发现URL是 /order.php/id/1000,
- 到晚上再次下单时发现URL变成了 /order.php/id/2000,
- 这样就可以推断出该网站当天大约处理了1000笔订单,
- 并据此估算出当天的销售额水平,
- 而这些数据往往都是重要的商业机密信息。
效率?
假如上述关于UUID的所谓缺点不成立,则唯一的问题就在于效率了。据称,在PostgreSQL等数据库中均设有专门的UUID类型,在这类数据库中采用.UUID作为主键并不会影响性能。
然而遗憾的是,在MySQL中并没有这样的字段。
如果要在MySQL中存储_uuid_作为主键,则通常采用CHAR(36)来模拟。
因为这不是一个原生的_uuid_类型。
所以主健性能尚待评估。
另外需要注意的是, uuid_做为主健的实际效果与其算法实现细节密切相关。
此外,在InnoDB这种基于主键索引的数据库引擎中,默认会对数据进行按照主键字段进行排序处理。然而,在实际应用中发现由于UUID具有无序性特点,在这种情况下会导致InnoDB产生过大的I/O压力因此不建议将UUID作为物理主键字段使用;相反则可将其作为逻辑指针字段来配置;同时仍需维持自增ID字段作为物理层面的唯一标识符。
在MySQL数据库中使用UUID作为主键索引列时,默认采用两种不同的存储方式:一种是将UUID存入char类型字段中并指定长度为36位;另一种则是将其以二进制形式存入binary类型字段并指定长度为16位。目前尚不清楚这种存储方法对其查询性能表现如何。
