能明确知道哪里会慢,为什么会慢
优化的本质是减少IO,减少随机IO,减少比较和排序(费cpu)
1. 关于主键
mysql8 innodb 表必定有主键,第一种方法是自己显示定义
如果没有显示定义,mysql 自动在表中添加
DB_ROW_ID |
(全局共享递增)
可以用 以下sql 查看隐藏列
show extended columns from `表名`
第一种观点 不能用UUID 做主键
https://www.percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/ UUIDs are Popular, but Bad for Performance — Let’s Discusshttps://opensource.actionsky.com/20191219-percona/ 这篇文章是 上一篇文章的翻译
原因:
1. innodb 聚簇索引需要排序导致页频繁拆分,这个是主要原因
2. UUID 太长,对于二级索引来说占用空间太大
3. UUID 是字符串,查询时用字符串比较效率低于整型
第二种观点 可用做主键
1. 替代方案 UUID_SHORT()
2. 参考文章
https://www.jianshu.com/p/0c5b477b2eb6 The UUID in MySQL8
https://blog.csdn.net/weixin_39531229/article/details/113670333 uuid 能当主键吗?
打算使用UUID,您应该阅读MySQL8.0中UUID的支持,推荐用binary(16) 存储UUID
CREATE TABLE t (id binary(16) PRIMARY KEY);
INSERT INTO t VALUES(UUID_TO_BIN(UUID()));
使用uuid_to_bin() 可能会改变MySQL的UUID实现的顺序行为
UUID是由32位16进制字符串组成(不算分隔符'-')如:
62ab1547-710f-11e8-9a58-5254007205d6
如果直接保存,则需要32个字符,utf8编码下占用96个字节,对于主键来说还是太长。
幸运的是UUID中的每个字符都是16进制字符,两个16进制字符占用一个字节,
这样可以轻松将UUID转换为binary(16),占用16个字节,所需空间大大减少,而且二进制字符串检索对比效率很高。
An option in MySQL 8 is to use the UUID_TO_BIN()
function with a second argument set to 1 which will make MySQL swap the
first and third groups of hexadecimal digits.
一个至关重要的问题是UUID的组成中将timestamp 部分的低位时间段(如毫秒)放在了前面,高位时间段(如年月日)放在了后面,
这会导致前面的字符变化很快,后面的变化很慢,从而使产生的UUID不能顺序自增。这会导致索引插入效率大大降低。
为解决这一问题,mysql8提供了两个函数:UID_TO_BIN(arg1) / BIN_TO_UUID(arg1,arg2)
UID_TO_BIN(arg1) 将UUID转化为16位二进制字符串,如果参数arg1为true则将UUID中的timestamp部分中的time-low(第一段字符)和time-high(第三段)调换,这样产生的UUID是顺序递增。
BIN_TO_UUID(arg1,arg2)将16位进制字符串转化为可读的UUID,arg1为16位二进制字符串,如果arg2省略或为false,即将二进制字符串原位转换;如果arg2为true,则将原来调换的time-low和time-high再调换回去,返回原本的uuid.
测试
创建一张表如下:
mysql8[test]>create table t (id varbinary(16) primary key,create_time timestamp default current_timestamp());
Query OK, 0 rows affected (0.34 sec)
插入几条数据,注意使用了函数uuid_to_bin:
mysql8[test]>insert into t (id)values(uuid_to_bin(uuid(),true));
Query OK, 1 row affected (0.08 sec)
mysql8[test]>insert into t (id)values(uuid_to_bin(uuid(),true));
Query OK, 1 row affected (0.08 sec)
mysql8[test]>insert into t (id)values(uuid_to_bin(uuid(),true));
Query OK, 1 row affected (0.07 sec)
查看结果:
mysql8[test]>select bin_to_uuid(id) id1,bin_to_uuid(id,true) id2, create_time from t;
+--------------------------------------+--------------------------------------+---------------------+
| id1 | id2 | create_time |
+--------------------------------------+--------------------------------------+---------------------+
| 11e87113-f079-024e-8405-5254004332fa | f079024e-7113-11e8-8405-5254004332fa | 2018-06-16 11:18:28 |
| 11e87113-f826-4134-8405-5254004332fa | f8264134-7113-11e8-8405-5254004332fa | 2018-06-16 11:18:41 |
| 11e87113-f88c-c8a6-8405-5254004332fa | f88cc8a6-7113-11e8-8405-5254004332fa | 2018-06-16 11:18:42 |
+--------------------------------------+--------------------------------------+---------------------+
3 rows in set (0.00 sec)
注意字段id1使用了函数bin_to_uuid(id), 而id2使用了bin_to_uuid(id,true),注意他们在结果集中的区别。
如果需要按主键查询,还是需要使用对应的uuid函数:
mysql8[test]>select * from t where id=uuid_to_bin('f079024e-7113-11e8-8405-5254004332fa',true);
+------------------+---------------------+
| id | create_time |
+------------------+---------------------+
| 篓