公司数据库账单单表存储过亿,急需优化

优化现有MySql

表设计

  • 表字段避免null值出现,null值很难查询优化,占用额外的索引空
  • 如果非负则加上UNSIGNED
  • 尽量使用TIMESTAMP而非DATETIME
TIMESTAMP:它把客户端插入的时间从当前时区转化为UTC(世界标准时间)进行存储。查询时,将其又转化为客户端当前时区进行返回。
DATETIME:不做任何改变,基本上是原样输入和输出。
  • 索引建立
在WHERE和ORDER BY命令上涉及的列建立索引,利用最左前缀原则:
值分布很稀少的字段不适合建索引
字符字段只建前缀索引
多个单列索引在多条件查询时只会生效第一个索引,所以多条件联合查询时最好建联合索引
离散度大(不同的值多)的列,放在联合索引前面。
...

外层优化

  • 通过Redis进行热点缓存
  • 通过Elasticsearch进行api对外查询的读写分离

分区[mysql支持的功能,业务代码无需改动]

  • 关于分区

    • 分区表底层是由多个物理子表组成,对应用是透明的,对分区表的请求会通过句柄对象转化为对存储引擎的接口调用。
    • MySql的分区表索引按照分区的子表定义,没有全局索引。
    • 查询优化:优化器根据分区函数过滤分区,让查询扫描更少的数据。用户的SQL语句是需要针对分区表做优化,SQL条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区
    • 避免分区表存在NULL值(NULL值会使分区过滤无效)
    • 对于原生的RANGE分区,LIST分区,HASH分区,分区对象返回的只能是整数值
    • explain partitions 查看分区执行计划
  • 分区类型

    • 范围分区(RANGE)
    允许将数据划分不同范围(从属于一个连续区间值的集合)[非null列]
      
    PARTITION BY RANGE(YEAR(separated))(
        PARTITION p0 VALUES LESS THAN(1995),
        PARTITION p1 VALUES LESS THAN(2000),
        PARTITION p2 VALUES LESS THAN(2005)
    );
    
    
     - 列表分区(LIST)  
    
    
     允许将数据划分不同范围(从属于一个枚举列表值的集合)[非null列]
     LIST分区只支持整形,非整形字段需要通过函数转换成整形.
     PARTITION BY LIST(category)(
         PARTITION P0 VALUES IN (3,5),
         PARTITION P1 VALUES IN (1,10),
         PARTITION P2 VALUES IN (4,9),
         PARTITION P3 VALUES IN (2),
         PARTITION P4 VALUES IN (6)
     );
    
    
     - 哈希分区(HASH)
    
    
         基于给定的分区个数,将数据散列到不同的分区(HASH分区的底层实现基于MOD取余函数)
         只能针对整数进行HASH,对于非整形的字段只能通过表达式将其转换成整数
           
         PARTITION BY HASH(id)
         PARTITIONS 4; -- 分区数
    
    
     - 哈希分区(LINEAR HASH)
    
    
     HASH分区的特殊类型,基于Power-of-Two算法...
    
    
     - KEY分区
    
    
	基于给定的分区个数,将数据散列到不同的分区(KEY分区的底层实现基于列的MD5算法)
	KEY分区对象必须为列,
	PARTITION BY KEY(id)
	PARTITIONS 2;
  • 分区的缺陷

    • 分区表,分区键设计不太灵活,如果不走分区键,很容易出现全表锁
    • 一旦数据量并发量上来,如果在分区表实施关联,很容易发生灾难
    • 对比分库分表:分库分表,自己掌控业务场景与访问模式,可控。分区表,基于mysql底层机制,不太可控
  • 分区的优势

    • 冷热分离:表非常大且只在表的最后部分有热点数据,冷数据根据分区规则自动归档
    • 定期淘汰历史数据:按时间写入,历史数据可淘汰,可快速删除,空间可快速回收
    • 优化查询:在where字句中包含分区列时,分区可以大大提高查询效率,减少缓存开销、减少IO开销
    • 统计性能提升:在涉及sum()和count()这类聚合函数的查询时,可以在每个分区上面并行处理,最终只需要汇总所有分区得到的结果。

分库分表[业务层改动实施]

  • 垂直拆分表 垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表,建议在数据表设计之初就执行垂直拆分
把不常用的字段单独放在一张表;
把text,blob等大字段拆分出来放在附表中;
经常组合查询的列放在一张表中;

image

  • 水平拆分表 水平拆分是指数据表行的拆分,把一张的表的数据拆成多张表来存放。
通常情况下,我们使用取模的方式来进行表的拆分,在insert时还需要一张临时表uid_temp来提供自增的ID,该表的唯一用处就是提供自增的ID;

image

  • client模式和proxy模式
    • client模式
      image
    • proxy模式
      image

无论是client模式,还是proxy模式,几个核心的步骤是一样的:SQL解析,重写,路由,执行,结果归并。 采用client模式,架构简单,性能损耗也比较小,运维成本低。如果在项目中引入mycat或者cobar,他们的单机模式无法保证可靠性,一旦宕机则服务就变得不可用,你又不得不引入其他中间件(HAProxy)来实现它的高可用集群部署方案

存储升级

升级MySql

  • 阿里云POLARDB 关系型分布式云原生数据库,100%兼容MySQL,存储容量最高可达 100T,性能最高提升至 MySQL 的 6 倍。 参考:https://yq.aliyun.com/articles/173291

参考