MySQL主键应该用UUID还是INT类型

卡拉先生
发布于 2020年09月06日 | 上次编辑:2020年09月07日

header

概要: MySQL中究竟应该用UUID还是INT作主键?都有哪些优劣?这篇教程会向你介绍 MySQL UUID 的概念,教你怎么用它来作为表的主键(PK),并且会讨论一下拿它做主键的优劣。

MySQL UUID 简介

UUID 的全称是 Universally Unique Identifier,也就是全局唯一标识的意思。它的详细定义可以查看 RFC 4122 规范里的 "A Universally Unique IDentifier (UUID) URN Namespace" 章节。

UUID 从设计上来讲,就是被用来表示一个全局唯一的字符串(无论从空间或时间上来说)。就算是两个完全独立的服务器上生成的两个 UUID,我们也可以基本认为它们的值不太可能相同(碰撞)。

在 MySQL 里,一个 UUID 值是一个128位的数字,它通过 utf-8 编码下的5个十六进制数字来表示,例如:

aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee

如果想要生成 UUID 的话,你可以使用 UUID() 函数:

UUID()

这个 UUID() 函数会返回一个符合 RFC 4122 标准中 UUID 版本1的 UUID 值。

例如,下面的示例代码就使用 UUID() 函数生成了一个 UUID 值:

mysql> SELECT UUID();
+--------------------------------------+
| uuid()                               |
+--------------------------------------+
| 865234ad-6a92-11e7-8846-b05adad3f0ae |
+--------------------------------------+
1 row in set (0.05 sec)

如果你还没有安装好 MySQL 的话,请参考教程Ubuntu如何安装MySQL,Linux 下安装都是共通的。如果登录有问题,请参考MySQL 创建新用户并授权教程

MySQL UUID 和自增 INT 型作为主键的比较

优势

使用 UUID 作为主键主要有下列优势:

  • UUID 值在不同的表、数据库、甚至是服务器中都是全局唯一的,所以你可以合并来自不同数据库,甚至是不同服务器上不同数据库上的数据行。
  • UUID 值不会在 URL 中暴露你的数据信息。例如,一个客户可以通过 id 10来访问他的账号地址 http://www.example.com/customers/10/ ,他可以很轻松地猜到会有 id 11, 12 等等的客户,这可能被拖库,或被别人猜到你的用户量
  • UUID 值生成的时候不需要查一遍数据库,并且它还简化了应用层的逻辑。例如,当你要给父表和子表插入数据时,一般你要先把数据插到父表里,然后才能插到子表里。但是如果你用 UUID 的话,你可以直接生成父表的主键,然后在一个事务里同时把数据插到父表和子表里。

劣势

除了优势以外,UUID 当然也是有劣势的:

  • 存储 UUID 值(16字节)需要的存储空间比 INT 型(4字节)甚至是 BIG INT 型(8字节)都要大。
  • 调试起来会更难一些,你可以想象一下平时你只需要 WHERE id = 10 现在你要写 WHERE id = 'df3b7cb7-6a95-11e7-8846-b05adad3f0ae
  • UUID 值通常会因为它的大小和未被排序的问题导致性能问题。

如果你在意性能的话,UUID 可能不是最好的方案。同样如果你在尝试构建搜索功能,可以尝试卡拉搜索,无需配置维护即可实现 MySQL 里千万行数据的毫秒级搜索,免掉全文索引的痛苦,让你能专注核心业务。

MySQL UUID 解决方案

在 MySQL 中,你可以借助这些函数,把UUID用一种压缩的格式(BINARY)存储,并用一个人类可阅读的格式(VARCHAR)展示。

  • UUID_TO_BIN
  • BIN_TO_UUID
  • IS_UUID

要注意 UUIDTOBIN(),BINTOUUID() 和 IS_UUID()仅在 MySQL 8.0或更高版本才能用

UUID_TO_BIN() 函数会把 UUID 从人类可阅读格式(VARCHAR)转化成压缩格式(BINARY)来存储,然后 BIN_TO_UUID() 函数会把 UUID 从压缩格式(BINARY)转化成人类可阅读格式(VARCHAR)来进行展示。

IS_UUID() 函数则会在参数是一个合法的 UUID 字符串时返回 1。在参数不是一个合法的 UUID 字符串时返回 0。如果参数是 NULL,那么该函数也会返回 NULL

下面这些都是 MySQL 里合法的 UUID 字符串

aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
aaaaaaaabbbbccccddddeeeeeeeeeeee
{aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee}

MySQL UUID 案例

接下来,我们来看一个使用 UUID 作为主键的例子吧

下面这些代码会创建一个新表,名字叫作 customers

CREATE TABLE customers (
    id BINARY(16) PRIMARY KEY,
    name VARCHAR(255)
);

要把 UUID 插到 id 一列里,你可以使用 UUID()UUID_TO_BIN() 函数:

INSERT INTO customers(id, name)
VALUES(UUID_TO_BIN(UUID()),'John Doe'),
      (UUID_TO_BIN(UUID()),'Will Smith'),
      (UUID_TO_BIN(UUID()),'Mary Jane');

如果要从一个 UUID 列中查询数据的话,那你要使用 BIN_TO_UUID() 函数来把二进制格式的 UUID 转换成人类可阅读的格式:

SELECT 
    BIN_TO_UUID(id) id, 
    name
FROM
    customers;   

MySQL-UUID
MySQL-UUID

到这里,你已经了解了 MySQL UUID,并且学会了如何使用它作为主键了。

总结

本文总结了在 MySQL 中使用 UUID 还是 INT 整型的优缺点,对多数常规应用来说,性能并不是瓶颈,推荐使用 UUID。如果使用 INT 整型,则有一些麻烦的地方,还有可能被拖库之类的安全隐患发生。

最后如果你刚好需要构建搜索功能的话,也可以尝试卡拉搜索,几行代码就可以接入,可以极大程序免去开发和维护一个搜索引擎的烦恼。

本文参考

MySQL主键使用自增还是UUID(Maple的博客)

小黄鸭的博客 - UUID方案很受欢迎,但是于性能不利

原文链接

相关文章

友情链接更新日志© 2020, 卡拉搜索, Built with ❤️ in San Francisco + Beijing

京ICP备15049164号-3