数据库-关系型数据库-Mysql的设计要点

83 阅读3分钟

解决的问题

  • 连接数太多
  • 数据查询慢(量大耗时长、连接太多CPU忙、连接池满等待)
  • 数据量太大(单表数据量超过单表最佳实践大小)
  • 可用性(单库/表损坏影响全部数据)
  • 单库瓶颈(磁盘IO、网络IO、CPU)

设计要点

  1. 根据一个阶段的用户量评估各表的数据量,进行高性能、高可用的架构设计;
  2. 根据是否核心数据,确定id生成策略,避免核心数据id产生冲突;
  3. 写入、查询性能等方面的细节设计。

架构设计

1. 高性能

  • 分库:按业务维度分库(例如微服务);同一个表因分表后数据量还是超过一个库的处理能力,需要分库+分表,或者有按常住地分区域服务的考虑需要分库+分表;
  • 分表:单表超1000w行或容量超20GB(某些旧系统的最大限制),需要考虑分表;
  • 分布式存储
  • 读写分离
  • 引入缓存
  • 引入消息队列

2. 高可用

(主备、主从bin_log)(策略:如果db进程不存在则自动拉起,如果主db连续1分钟连接不上,则主从切换)

  • 分布式存储

细节设计

并发性能

  • 主键设计:非核心业务使用自增(不单调问题在8.0已修复,不连续问题可忽略)、核心业务使用单调递增(例如MySQL 8.0提供uuid_to_bin)

写入性能

  • 外键设计:一般不设置,由代码维护(分库分表、并发死锁{加父表共享锁}、性能问题{一致性检查、级联操作可能引发雪崩}、测试不方便)
  • 字段类型及长度、时间的类型选择(date/time/datetime/timestamp/year)、统一字符集(utf8mb4)
  • 逻辑删除
  • 如果插入数据过多,考虑批量插入
  • 通用字段(version乐观锁)
  • 索引优化:
    • 索引个数不超5个
    • 字符串比较长时建索引,可取前缀建索引

查询性能

  • 大字段:浪费存储空间,查询效率也不好,可以转为存url或mongodb文件存储(延迟加载),例如评论、图片
  • 字段尽量NotNull(否则索引失效、比较大小复杂、优化器难、使用会出现空指针)
  • 索引优化:
    • 覆盖索引、
    • 条件最左匹配索引
    • 对索引字段运算或函数,索引会失效
    • 区分度不高的不要加索引
  • SQL优化:
    • 查询SQL尽量不要使用select *,而是select具体字段
    • 如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1
    • 应尽量避免在where子句中使用or来连接条件
    • 注意优化limit深分页问题
        1. 前端限制深度(百度、谷歌方案)
        1. 记录每次取出的最大id, 然后where id > 最大id
        1. join方式 + 覆盖索引(推荐)
        1. IN获取id
      • 如果对于有where 条件,又想走索引用limit的,必须设计一个索引,将where 放第一位,limit用到的主键放第2位,而且只能select 主键!
    • 使用where条件限定要查询的数据,避免返回多余的行尽量避免在索引列上使用mysql的内置函数应
    • 尽量避免在 where子句中对字段进行表达式操作
    • 应尽量避免在where 子句中使用!=或<>操作符
    • 使用联合索引时,注意索引列的顺序,一般遵循最左匹配原则。
    • 对查询进行优化,应考虑在where 及 order by涉及的列上建立索引
    • 在适当的时候,使用覆盖索引
    • 使用explain 分析你SQL的计划
  • 表优化
    • 表最大3000w行

其他注意点

  • 存储过程&触发器:不建议使用(没有完善的出错记录)
  • 消除N:N:如果两张表存在N:N关系时,应该尽量消除这种关系。通过增加第三张表,把N:N修改为两个 1:N。(如果想优化查询除外)