用户 id 生成、一般类 id 生成的数据类型和方法选择

本贴最后更新于 1394 天前,其中的信息可能已经物是人非

核心问题

一个项目中,我把 id 划分为两类,一种是要求“可读性”,另一种是单纯用来表示 id,不要求“可读性”。

比如:

  1. 要求“可读性”:用户的 id,不能用一串 32 位或者 64 位长的数字,这样人眼看起来体验很差。常见的 id 比如 qq 号,使用一串 10 位长的数字。像这种我称其为需求“可读性”强的 id
  2. 不要求“可读性”:系统内部的 id,比如某个文件的 id 号,某个数据统计行的 id。这些都是人不需要肉眼看的 id,格式和长度可以不考虑人眼的可读性。

请问这两种类别的 id,各自选择什么数据类型,用什么方法生成比较好呢?

数据规模

目前项目是一个微信小程序的后端,预计数据量一张表最多 10w 行。

当然数据量规模不大的话,主键选择什么数据类型、生成方法都没关系。虽然我的项目预计数据量不多,但我想尽量规范一些,用更好的办法。

目前项目中使用的方法

目前在我的项目中,关系型数据库为 mysql,引擎 Innodb。使用考虑到 Innodb 的 B+ 树结构,主键采用 auto_increment 的方式,可以更好地一页一页排下去。详细请见:为什么 InnoDB 表最好要有自增列做主键 ?。但是我不想使用自增主键作为业务主键。于是采用:“代理主键”和“自然主键”:

自然主键:就是充当主键的字段本身具有一定的含义,是构成记录的组成部分,比如学生的学号,除了充当主键之外,同时也是学生记录的重要组成部分。

代理主键:就是充当主键的字段本身不具有业务意义,只具有主键作用,比如自动增长的 ID。

建表所用 sql:

create table `user_info` (
    `id` int not null auto_increment comment '代理主键',
    `uid` varchar(32) not null comment '用户uid,唯一键',
    primary key (`id`),
    unique key `uk_user_info_uid` (`uid`)
) comment '用户表';

代理主键通过 auto_increment 生成。自然主键自行生成,生成自然主键的工具类:

@Slf4j
public class UniqueKeyUtil {
    /**
     * 生成不重复的11位字符串
     * 10进制转16进制
     * 高并发情况下可能会出现重名,所以需要使用synchronized关键词来修饰
     * @return
     */
    public static synchronized String getUniqueKey() {
        long randomInteger = System.currentTimeMillis();
        // 睡眠1ms,避免出现重复的key
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            log.error("[UniqueKeyUtil]Thread.sleep() error, errMsg = {}", e.getMessage());
        }
        String hexString = Long.toHexString(randomInteger);
        return hexString;
    }
}

在开发项目的过程中,我突然意识到一个问题:自然主键使用 varchar 类型,检索速度不如 int, bigint 这样的类型。
现在有些懊悔,想要把自然主键的 varchar 类型改为 int 或者 bigint 类型。但更改主键是一件高风险、复杂度较高的事情。例如:

  1. 更改自然主键的数据类型后,现有数据的 id 转换到新数据类型的可行性存疑。
  2. 项目中很多处用到了 id,贸然更改数据类型,遇到坑的概率可能比较大。

当前项目中的自然主键,全部使用的 varchar(32),我感到惶恐不安,感觉自己拖累了项目的运行速度。我不知道我是否应该变更自然主键的数据类型。

  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    330 引用 • 614 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6364 引用 • 28618 回帖 • 264 关注
4 操作
JellyfishMIX 在 2020-06-04 15:02:54 更新了该帖
JellyfishMIX 在 2020-06-04 15:02:41 更新了该帖
JellyfishMIX 在 2020-06-04 14:44:24 更新了该帖
JellyfishMIX 在 2020-06-04 14:41:22 更新了该帖

相关帖子

被采纳的回答
  • 88250 1
    1. 你开头也提到,这个数据量级上不必考虑 id 类型带来的性能问题
    2. “过早的优化是万恶之源”,好的设计方案是简单够用的,不要追求复杂完美
    3. 即使出现性能问题,多半也是因为业务场景或者实现 SQL 有问题,这些影响比主键类型带来的影响大很多

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • 88250 1
    1. 你开头也提到,这个数据量级上不必考虑 id 类型带来的性能问题
    2. “过早的优化是万恶之源”,好的设计方案是简单够用的,不要追求复杂完美
    3. 即使出现性能问题,多半也是因为业务场景或者实现 SQL 有问题,这些影响比主键类型带来的影响大很多
    1 回复
  • JellyfishMIX
    作者

    简短精悍,明白了,谢谢 D 哥!