解决的问题
- 连接数太多
- 数据查询慢(量大耗时长、连接太多CPU忙、连接池满等待)
- 数据量太大(单表数据量超过单表最佳实践大小)
- 可用性(单库/表损坏影响全部数据)
- 单库瓶颈(磁盘IO、网络IO、CPU)
设计要点
- 根据一个阶段的用户量评估各表的数据量,进行高性能、高可用的架构设计;
- 根据是否核心数据,确定id生成策略,避免核心数据id产生冲突;
- 写入、查询性能等方面的细节设计。
架构设计
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深分页问题
-
- 前端限制深度(百度、谷歌方案)
-
- 记录每次取出的最大id, 然后where id > 最大id
-
- join方式 + 覆盖索引(推荐)
-
- 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。(如果想优化查询除外)