记一次生产事故及分析MySQL为什么不推荐使用UUID或雪花id作为主键

1.事故描述

1.1 业务需求

主表保存个人基本信息,子表保存受伤情况记录

1.2 事故描述

需要保存用户两次受伤情况,受伤描述分别为“事故描述1”、“事故描述2”,查询结果为:”事故描述2“、”事故描述1“,与期望结果相反

数据库记录如下
在这里插入图片描述

1.3 事故分析

页面查询结果采用默认排序方式,InnoDB使用默认排序方式查询数据时,默认会根据主键排序,由于主键使用UUID,导致数据库不会按照插入的顺序进行排序,导致查询出的数据不满足期望要求。

1.4 解决方案

  1. 为数据库表增加字段用于查询时排序,保证按照插入顺序进行排序
  2. 使用自增ID代替UUID
  3. 修改数据库表引擎为MyISAM(MyISAM默认按照插入顺序排序)

2.MySQL为什么不推荐使用UUID或雪花id作为主键

2.1MySQL索引的数据结构

InnoDB存储引擎下使用B+树的数据结构,每个节点不保存数据,只用来索引,所有数据都保存在叶子节点上。所以每个表都会创建一个主键索引,不管是否指定了主键,B+树节点上保存的是主键索引,并且必定是有序的。

在这里插入图片描述
2.2 数据操作步骤分析

由于B+树存储的数据是有序的,当有新的数据插入时,如果数据是有序的(自增ID),那么数据将直接插入到到末尾处;如果数据是无序的(UUID/雪花id等随机生成的id),为了保证数据的有序性,那么数据将有可能插入到已有的数据中间,后面的数据将依次往后移位。

MySQL中存储数据的最小单元是page(页),大小为16KB,也就是说一个page可以存储多个数据。我们分析这样一种情况,当page1已经存满,page存了部分数据时需要插入一条数据,如果此时使用的自增ID,即数据是有序的,那么数据将直接插入到末尾,如果数据是无序的呢?

显然,为了保证数据有序性,数据有可能被插入到page1中,但此时page1已经满了,那么插入数据后面的数据都必须往后移动,存不下的数据只有移动到page2,此时就发生了page的分裂与合并,会大大影响数据的插入和删除,这也就是为什么MySQL不推荐使用UUID或雪花id这类随机id的原因。