我们在拿到这个问题的时候,需要先分析一下,正常用户表有哪些字段,然后根据这些字段来设计表结构。这样我们就有了一张基础的用户表。
有了用户表之后,就要解决一亿用户的存储问题,一亿用户肯定不能存储一张表中,这样会导致性能问题。这个时候就需要使用分库分表、或者使用分区表。总之,目的是将数据范围缩小,提高查询性能。
解决掉数据存储的问题之后,我们还要回到业务中,一亿用户的系统,对于数据库的操作肯定很频繁。这个时候就需要使用数据库的索引来提高查询性能、读写分离分担数据库压力、以及使用缓存系统来提高系统的响应速度等。
最后建立完善的监控体系,监控数据库的性能、慢查询、异常等,保证系统的稳定性。
基础的用户表需要包含用户id、用户名、密码、手机号、邮箱、注册时间、最后登录时间、状态等字段。以及数据库的一些基础字段,比如创建时间、更新时间、删除时间等。
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(50) NOT NULL COMMENT '密码',
`phone` varchar(20) NOT NULL COMMENT '手机号',
`email` varchar(50) NOT NULL COMMENT '邮箱',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
`status` tinyint(4) NOT NULL COMMENT '状态',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_phone` (`phone`),
UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
id
字段使用bigint
类型,因为用户量很大,使用bigint
可以保证存储用户id的位数。username
、phone
、email
字段使用varchar
类型,因为用户名、手机号、邮箱都是字符串类型,使用varchar
可以保证存储的灵活性。password
字段使用varchar
类型,因为密码也是字符串类型,使用varchar
可以保证存储的灵活性。status
字段使用tinyint
类型,因为状态只有两种,使用tinyint
可以保证存储的灵活性。有了基础表之后,我们可以对字段类型进行优化:
create_time
、update_time
、delete_time
字段使用timestamp
类型,因为时间戳可以保证存储的精确性。减少存储空间。还可以使用CURRENT_TIMESTAMP
、ON UPDATE CURRENT_TIMESTAMP
等默认值,减少数据库操作。优化后的表结构:
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(50) NOT NULL COMMENT '密码',
`phone` varchar(20) NOT NULL COMMENT '手机号',
`email` varchar(50) NOT NULL COMMENT '邮箱',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_time` timestamp NULL DEFAULT NULL COMMENT '删除时间',
`status` tinyint(4) NOT NULL COMMENT '状态',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_phone` (`phone`),
UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
由于用户量很大,单库单表无法满足需求,需要使用分库分表来提高数据库的存储能力。分库分表的方式有很多种,比如按照用户id取模、按照用户注册时间取模等。在这里我们按照用户id取模的方式进行分库分表。
首先我们需要一张用户id生产表,用于生成用户id。表结构如下:
CREATE TABLE `user_id` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户id生产表';
每次新增用户时,先从用户id生产表中获取一个用户id,然后插入到用户表中。
分布分表解决了数据的存储和查询问题,但是如何保证唯一字段的唯一性呢?这个就需要在业务实现上进行控制了。例如使用redis的布隆过滤器来保证用户名、手机号和邮箱的唯一性等。
分区表可以将数据按照一定的规则分散到多个物理文件中,从而提高查询性能。例如,我们可以按照用户ID进行分区,将用户数据分散到不同的分区中,从而提高查询性能。但是根据其他字段的查询性能可能会下降,因为分区表是根据分区键进行分区的,其他字段的查询需要扫描所有分区,所以要根据业务需求来选择是否使用分区表。针对这部分可以单独优化。