51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

设计一个用户表(User),考虑高并发下的读写分离、分库分表,请说明表结构设计(如主键、索引)、分库分表策略(如按用户ID哈希分库、按时间分表),并分析这些设计对系统性能和扩展性的影响。

快手Java开发工程师 📦 工程类难度:中等

答案

1) 【一句话结论】

用户表设计需结合读写分离(主库写、从库读)与分库分表(哈希分库+时间分表),主键用雪花算法保证唯一有序,通过索引优化高频查询,确保高并发下读性能提升、写性能通过分库扩展,系统可水平扩展,同时通过分布式事务与缓存减少数据库压力。

2) 【原理/概念讲解】

  • 读写分离:将数据库分为主库(处理写操作,如用户注册、登录、状态更新)和从库(通过Binlog复制主库数据,处理读操作,如查询用户信息、历史数据)。类比:超市收银台(主库)处理支付(写),自助结账机(从库)处理商品信息查询(读),减少排队时间,提升读吞吐量。
  • 分库分表:将数据水平拆分到多个数据库或表,解决单库容量、性能瓶颈。类比:把一个大仓库(单库)分成多个小仓库(分库),每个小仓库放一部分商品(数据),取货(查询)更快,且能加更多小仓库(扩展)。
  • 分库分表策略:
    • 哈希分库:按业务键(如用户ID)哈希,分配到不同库,负载均衡,适合用户量极大场景(如快手数亿用户)。
    • 时间分表:按时间(如月、年)分表,数据按时间有序,便于归档,适合有生命周期的数据(如用户行为日志、历史数据)。

3) 【对比与适用场景】

方案定义特性使用场景注意点
读写分离主库写,从库读读操作分散,写集中读多写少(如用户表,读远多于写)需数据同步,避免主从延迟导致不一致
哈希分库按用户ID哈希,分配到不同库水平扩展,负载均衡用户量极大(如快手数亿用户),单库无法承载需全局ID生成器(如雪花算法),避免热点库
时间分表按时间(如月)分表数据按时间有序,便于归档数据有生命周期(如用户注册记录、行为日志)需定期清理旧表,查询时需按时间范围过滤

4) 【示例】

  • 表结构:
    CREATE TABLE user (
        id BIGINT NOT NULL COMMENT '雪花算法生成,唯一有序',
        username VARCHAR(50) NOT NULL COMMENT '用户名,唯一',
        password VARCHAR(100) NOT NULL COMMENT '密码,加密存储',
        email VARCHAR(100) UNIQUE COMMENT '邮箱,唯一',
        create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
        status TINYINT DEFAULT 1 COMMENT '状态:1-正常,0-禁用',
        PRIMARY KEY (id),
        INDEX idx_username (username),
        INDEX idx_email (email),
        INDEX idx_status (status)  -- 覆盖索引,提升status查询性能
    );
    
  • 分库分表策略:
    • 分库:假设库数量为8,用户ID取模(id % 8)分配到对应库(如库0~7)。
    • 分表:按月分表,表名格式为user_202401(2024年1月),每月新增一张表,旧表归档(如2023年12月及以前数据)。
    • 路由示例:
      # 分库
      db_index = user_id % db_count  # db_count=8
      # 分表
      table_index = year(create_time) * 12 + month(create_time)  # 2024年1月为13
      table_name = f"user_{year}_{month}"
      # 查询时路由
      SELECT * FROM user_{year}_{month} WHERE id = ?;
      
  • 索引设计说明:
    • username和email的联合索引:用于按用户名或邮箱查询用户(高频操作,如登录、找回密码)。
    • status的覆盖索引:用于查询用户状态(如筛选正常用户),避免回表。

5) 【面试口播版答案】

用户表设计上,首先考虑读写分离,主库写,从库读,提升读性能。主键用雪花算法生成(时间+机器ID+序列号),保证唯一有序。然后分库分表:分库按用户ID哈希(比如8库,id % 8),分表按时间(按月),表名user_202401。索引方面,对username、email做联合索引,status做覆盖索引,提升查询性能。这样读操作分散到多个从库,写操作集中在一个库,同时数据按时间拆分,避免单表过大。性能上,读吞吐量提升(比如从单库的1万QPS提升到8库的8万QPS),写性能通过分库扩展(比如单库写压力从1000TPS提升到8库的8000TPS),扩展性方面,用户量增长时,增加库或表即可,不影响现有系统(比如用户量从1亿到10亿,只需加更多库或表,无需重构)。

6) 【追问清单】

  • 问:如何处理跨库操作的一致性(如用户注册时同时插入用户表和用户行为表)?
    答:采用分布式事务方案(如Seata的AT模式),通过全局事务协调器保证跨库操作的一致性;或用最终一致性(如TCC模式),通过补偿机制确保数据最终一致。
  • 问:如何设计缓存策略减少数据库读压力?
    答:用Redis缓存热点数据(如用户信息、常用查询结果),设置合理过期时间(如用户信息缓存5分钟),并采用缓存穿透、雪崩、击穿防护机制(如布隆过滤器、限流)。
  • 问:分库数量如何动态调整?
    答:根据用户量增长模型(如月增长20%),当用户量达到阈值(如当前库写压力超过阈值)时,增加分库数量(如从8库扩展到16库),通过路由规则动态更新。
  • 问:覆盖索引是否适用于所有status查询?
    答:若status查询频率高且数据量小,覆盖索引有效;若复杂查询(如按status+时间范围),需结合复合索引优化。

7) 【常见坑/雷区】

  • 主键设计不当:用字符串或无序ID(如UUID),导致分库分表后热点库,性能下降(比如所有用户ID哈希到同一库)。
  • 分库分表策略不合理:按用户ID范围分表(如按ID区间分表),导致热点表(比如新用户集中到某表),或分库数量过少(如用户量增长后,库不足导致性能瓶颈)。
  • 读写分离延迟:从库数据延迟(如Binlog延迟),导致读操作返回旧数据(比如用户刚更新状态,读不到最新状态),影响业务。
  • 缓存未结合:未用缓存减少数据库压力(如所有读操作都查数据库),导致读性能仍不足(比如Redis缓存热点数据,减少数据库压力)。
  • 分表键选择不当:按用户ID范围分表(如按年龄分表),导致查询时需要扫描多个表(比如查询18-25岁用户,需要查多个表),性能下降。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1