Java开发和MySQL DBA关于uuid干架友好的解决了

816 阅读4分钟

MySQL开发规范中经常可以看到:

  • 推荐使用int,bigint 无符号做自增键

  • 禁止使用uuid做主键

这是为什么呢? 原因: 现在使用MySQL基本默认指的InnoDB引擎,InnoDB是聚集索引表,所有的数据按主键排序存储。所以对于从小到大的数据做主键插入不会引起数据页的拆分,可以实现数据高效的写入,另一方面普通索引包含主键存储,所以要求主键尽可能的短小,减少空间的浪费。 对于使用自增列(int 4byte,bigint 8byte),如果使用uuid产生的是一个无序的36byte的字符(前面是乱的),造成写入的性能会越来越差,表的数据量在1000万以内,可能性能差别还不大。

怎耐开发使用uuid做一个对象的唯一引用已经成为习惯,就是爱用!

  • 对象的唯一性

  • 复杂的URL

  • 不同系统的数据的唯一标识

  • ...

所以MySQL8.0也是顺应时代潮流,担负时代的革命重任,MySQL8.0也对uuid的存储做了进一步的提升。整体上看MySQL8.0现在的重点方向也是对开发的友好度支持上。

那接下来直接上结论:

  1. 在MySQL8.0中还是推荐使用无符号的int, bigint做主键,如果要使用uuid可以建一个唯一索引

  2. MySQL和Java两者默认生成的uuid是version 1格式:datetime|mac地址,因为高低位顺序乱了,造成顺序乱掉,可以使用MySQL的函数uuid_to_bin(@uuid,1) , bin_to_uuid(@uuid,1)进行调整转换,实现有序化

  3. 对于使用uuid_to_bin转化后的uuid存储,使用binary(16)或是varbinary(16)替代varchar(36),从而实现从36byte降到16byte。

使用参考

  1. 产生一个uuid

    mysql> set @uid=uuid();

  1. 查看这个uuid的长度

    mysql> select @uid, char_length(@uid), length(@uid);

3. 转换成binary进行查看

mysql>set @uid16=uuid_to_bin(@uid,1);

mysql>select @uid16,bin_to_uuid(@uid16,1), char_length(@uid16), length(@uid16);

4.  注意如果bin_to_uuid或是uuid_to_bin不带第二个参考1,不会对uuid顺序优化,可能造成结果是错的。

mysql> select bin_to_uuid(@uid16), @uid, bin_to_uuid(@uid16,1);

5. 建个表操作一下:

mysql> create table tuid(uid binary(16), c1 datetime, primary key(uid));

Query OK, 0 rows affected (0.02 sec)

10次写入:

mysql> insert into tuid(uid) values(@uid16),now(); Query OK, 1 row affected (0.01 sec)

查看一下结果,体会使用情况:mysql> select hex(uid), bin_to_uuid(uid,1),c1 from tuid;

hex(uid)bin_to_uuid(uid,1)c1
11EBD1BBBB77DD029ED60242AC110002

|

bb77dd02-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:19

| |

11EBD1BBBCAFC7599ED60242AC110002

|

bcafc759-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:21

| |

11EBD1BBBD3F9D749ED60242AC110002

|

bd3f9d74-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:22

| |

11EBD1BBBDB8A6739ED60242AC110002

|

bdb8a673-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:23

| |

11EBD1BBBE298AF39ED60242AC110002

|

be298af3-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:24

| |

11EBD1BBBE95377A9ED60242AC110002

|

be95377a-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:25

| |

11EBD1BBBEFCF7519ED60242AC110002

|

befcf751-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:25

| |

11EBD1BBBF78901A9ED60242AC110002

|

bf78901a-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:26

| |

11EBD1BBCAD7743A9ED60242AC110002

|

cad7743a-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:36:45

| |

11EBD1BBE59D75C29ED60242AC110002

|

e59d75c2-d1bb-11eb-9ed6-0242ac110002

|

2021-06-20 11:37:30

|

10 rows in set (0.00 sec)

写在最后:这个技巧不是万能的,如果你的数据库CPU是瓶颈,使用转化存储,可能带来CPU上更重的开销,反之,如果你的IO是瓶颈,但CPU有较大的空闲,使用这个技巧就是一个不错的优化方案。如果不好把握,就用你可以用得到的最好硬件就可以了,一般情况下如果用上SSD后IO都没啥问题,但也可以使用这个技术去降低表的物理大小。END祝各位老板GL。

参考:

docs.oracle.com/javase/7/do… dev.mysql.com/doc/refman/…

本文使用 文章同步助手 同步