龙空技术网

总监说谁再用UUID()做主键,谁就走人!

架构师优雅之道 140

前言:

如今兄弟们对“mysql 主键uuid”大约比较关注,你们都想要知道一些“mysql 主键uuid”的相关资讯。那么小编也在网上汇集了一些关于“mysql 主键uuid””的相关知识,希望兄弟们能喜欢,大家快快来学习一下吧!

选择大于努力,选择不对,努力白费。

在进行数据库表结构设计的时候,主键的定义是个不容忽略的问题。

为什么同样的数据量,性能差别很大?

如何定义合适的主键呢?

本文主要探讨主键的使用,文章内容基于MySQL 8.0 Innodb存储引擎,其他数据库或者存储引擎可能略有差异,甄别对待。

为了方便阅读,每节的课代表部分做了总结,可以直接跳转。

主键数据类型选择

贾明是一个程序员,正在主导一个项目的开发,在设计表结构的时候,关于主键如何定义,在组内讨论的时候分歧很大。

有的同事倾向于使用UUID,理由是唯一不重复,值可以具有业务含义。

有的同事倾向于使用数值,使用数据库提供的自增特性,理由是占用空间少,而且插入数据不会导致索引重排。

每个人都有每个人的立场,每个人的观点明确并且理由充分。

选择是个艺术性的问题,选A必然要舍弃B,选B必要要舍弃A。于是,贾明结束了当次会议。

主键的作用自不必说,不了解的可以参考我之前的一篇文章主键外键“键键不止”,他们都是干什么的?。

在MySQL中,索引结构是B+Tree的数据结构。索引相关内容比较多,不展开,具体内容可以参考我的一篇文章三言两语聊MySQL 索引。

先来简单的介绍下,

索引的结构是B+Tree,数据有序,存储在数据页内。

关于数据页,这里需要关注两点:

数据页固定大小是16K数据页内,数据页之间主键都是从小到大有序排列的。

如果主键的值是无序的,那么在插入的时候,会根据主键值进行查找,找到一个合适的位置插入。如果当前页满了,就会新建一个页,将后边的数据进行移动。

而如果主键的值是有序的,那么只需要在树的尾部进行插入操作即可,页满了,直接新建一个页写即可。

索引结构,图片来自网络,侵删 索引结构,图片来自网络,侵删

到了这里,结论自然浮出水面:

数据类型占用空间尽可能少数据有序

第一点很好理解,索引本身也是数据,越小意味着在相同的页内能存储更多的数据,在数据检索的时候,可以减少IO查询。

有序是依据B+Tree的特性而言的,无序的索引结构意味着会造成索引分页等情况。

课代表

在选择主键数据类型的时候,要选择占用空间少的数据类型,并让主键值有序。如果您还有其他的看法,欢迎评论区讨论。

主键值有序设置

前面我们讲了,主键要选择数值类型,而且值要有序。

有哪些方式可以保证数据有序呢?

相信不少人在建表的时候,都会使用如下语句:

CREATE TABLE table_name (`id` INT(10) unsigned not null AUTO_INCREMENT,...) ENGINE=InnoDB;

MySQL支持在建表的时候,直接设置自增。AUTO_INCREMENT的用法是插入数据的时候如果没有指定列的值,会自动生成一个自增值,如果指定了,会先进行判断,如果插入值比当前值大,使用当前值,否则忽略,按照没指定值处理。

值得注意的是在MySQL8之前AUTO_INCREMENT的值是存储在内存中的,每次重启会初始化成当前表中的最大值,8.0之后,AUTO_INCREMENT做了持久化,重启后是建表以来的最大值。

可不可以不用AUTO_INCREMENT呢?当然可以,自己维护一个自增值就可以了。

课代表

使用AUTO_INCREMENT设置主键自增。也可以自己维护一个自增值。如果您还有其他的看法,欢迎评论区讨论。

主键要不要做业务字段

主键赋予业务含义,可以不可以做业务字段,从技术上是没问题的,但是从业务上来讲存在安全隐患。

举个例子,用户表,如果主键用来做人员ID,很容易被竞争对手发现总用户数是多少,每月新增用户数多少。现在大家平时叫外卖比较多,在小票上,很容易就能发现今天有多少订单,而这些是商业机密,相信任何人也不想把这些数据暴露出来。

因此建议不要将主键用作业务字段,当然,如果不把主键暴露给前段,当我在自言自语。

课代表

主键应避免做业务字段,如果确实要用,要防止数据安全性。如果您还有其他的看法,欢迎评论区讨论。

分布式环境下该怎么处理

分布式越来越盛行的今天,不止是应用,数据库也会做分布式,比如有两张用户表,分表后,主键值该怎么处理,如果还使用自增,这不就重复了吗?违背了主键的唯一性原则。

这里,就要考虑一种合适的方案来生成主键值了。业界常用的有两种方式:

使用Redis,Redis的Incr可以将存储的数值+1,在进行写入的时候,先在Redis中生成一个,然后在插入的时候写入该值。部署一个ID生成服务,主流方式,一般会单独部署一个服务来生成ID值,这个服务来保证生成一个唯一不重复的有序值。

两种方式各有优劣,Redis的好处是自己不需要维护ID的生成,缺点就是如果出现宕机,可能会生成重复值。自己部署一个需要维护ID 生成策略,不过业界也有主流的方式,像雪花算法,关于雪花算法的内容,可以参考我的一篇文章。

此外,还需要考虑单点故障及并发。如果服务不可用,会影响数据的插入。有时间会专门聊一下在分布式环境下如何正确生成ID。

课代表

可以自己部署个ID生成的服务,自己实现或者使用Redis。如果您还有其他的看法,欢迎评论区讨论。

本文主要讲了主键字段类型选择和值的生成,由于”知识的诅咒“现象,可能存在疏漏,恳切希望得到您的建议和意见。

标签: #mysql 主键uuid