Mysql千万级大表优化方案_Mysql

在日常开发任务中,经常会遇到单张表过1千万,以每天n万条的速度进行递增。sql查询效率下降,前端业务表现为用户操作缓慢,如查sql查询速度超过1秒或者更长,会发生一条sql把整个数据库连接占满,用户看到的就是白页面或报错的页面。

mysql数据库存储是系统最后一道护城河,以最谨慎的态度对待。系统就像一个成长的小树,慢慢的长大,每一天的成长都需要不停的修剪、不停的优化。

关于大表的优化常见的思路就是分表、分库、数据分区,降低单表容量,提高单表查询速度。可是细细想来,优化不仅仅是分表分库简单的操作,而是站在系统设计的角度去考虑。


秩序是自由的第一条件

1 数据量过千万的不同场景

1)数据量千万级,随着时间快速增长。

     这样的表大多是订单表、日志表。过亿只是时间问题。

2)数据量千万级,相对变化缓慢

      例如用户表在增长的过程中一般不会爆炸式的增长。

3)审视业务

      虽然有过千万的数据,这些数据是否都合理,是否要长期维护。与产品业务进                  行沟通数据的存在合理性。

 

2 优化

1)规范设计

2)业务层优化

3)架构层优化

4)数据库优化

5)管理优化

 

1)规范设计

做java程序开发一般都会参考阿里编程规范,一个技术团队统一的编码规范、编码样式可以有效的规避很多不必要的技术坑。但是数据库是在开发、生产、运维中最重要的一个环节,很多时候忽略了对数据库的重视程度。数据库的设计规范与java编码规范同等重要。

 

配置规范

(1)具有事务型的产品,数据库存储引擎统一使用InnoDB

(2)创建操作系统、数据库、表统一使用UTF8,jdbc连接字符集、各展示层统一使用UTF8,避免了很多乱码的问题。

(3)数据库单表容量合理的规划、建议单表容量在2000万内。如果超过2000万就要考虑优化数据库架构、程序逻辑。

(4)单库数据表容量不要超过500个,表通过前缀的方式区分业务

 

建表规范

(1)InnoDB不能使用外键约束,java在逻辑层进行关联。

(2)存储浮点数使用decimal,不要使用float double。

(3)尽量不要使用text、blob。

(4)字段设置not null ,为字段定义默认值。

(5)建立sql上线规范,dba终审上线脚本。

 

命名规范

(1)库名、表名、字段名、索引名统一小写,单词之间用下划线分割。

(2)对象命名规范

视图viewview_
函数functionfunc_
存储过程procedureproc_
触发器triggertrig_
普通索引indexidx_
唯一索引unique indexuniq_
主键索引primary keypk_

 

 

索引规范

(1)索引建议命名规则:idx_col1_col2[_colN]、uniq_col1_col2[_colN](如果字段过长建议采用缩写)。

(2)索引中的字段数建议不超过5个。

(3)单张表的索引个数控制在5个以内。

(4)InnoDB表一般都建议有主键列,尤其在高可用集群方案中是作为必须项的。

注:主键设计,如果后续分库、分表不建立使用自增id、建立全局生成唯一id。

建立微服务,统一生成。

(5)建立复合索引时,优先将选择性高的字段放在前面。

(6)UPDATE、DELETE语句需要根据WHERE条件添加索引。

(7)不建议使用%前缀模糊查询,例如LIKE “%weibo”,无法用到索引,会导致全表扫描。

(8)合理利用覆盖索引,例如:

SELECT email,uid FROM user_email WHERE uid=xx,如果uid不是主键,可  以创建覆盖索引idx_uid_email(uid,email)来提高查询效率。

(9)避免在索引字段上使用函数,否则会导致查询时索引失效。

(10)上线前要经过dba评审

 

2)业务优化

  • 业务拆分

  • 数据拆分

  • 读多写少优化

  • 写多读少优化

 

业务拆分

业务拆分同样表述为垂直拆分、根据业务把业务表拆分到不同的数据库。例如新浪微博,用户基础信息库、微博信息库、评论库。

通过拆分数据库让业务数据更清晰,同类的数据在同一个库,同时提高整个系统的并发度。上层业务代码层,通过建立用户服务、与各业务微服务建立通信,让各系统间通过rpc进行调用。

 

数据拆分

1.按日期拆分

按日期进行拆分是比较常见的一种拆分方式,例如把订单历史数据拆分为,当天表、当月表、再按月进行分表

 t_order_day

 t_order_202010

 t_order_202009

 如此拆表会产生另外一个程序编写的问题,有可能用户要跨月进行查询订单,一个季度要跨3张表进行查询,可以通过在java层聚合数据。

 再深入一点的思考,如果用户有可能在09 07 03这三张表里有数据,其他表里没有数据,就有可能让程序发空的sql进行扫描。可以维护一个用户订单数据在哪张历史表的缓存表,在用户登陆的时候异步把数据缓存到redis中,在查询的时候直接就可以知道去哪些历史表中查询。

 

2.读多写少优化

增加redis缓存,把数据同步到redis,让请求命中到redis中

 

3. 写多读少优化

异步提交、消息队列、批量写入

异步提交,可以通过多线程的方式处理任务,即时给客户端响应。

消息队列,可以使用jvm消息队列,分布式消息队列。

批量写入,需要处理的请求一瞬间暴增的时候,可以在消息队列的消费者累计1000   或一定数量的记录,进行batch批量更新。

 

3)架构优化

  • 系统水平扩展

  • 离线统计业务

 

1)系统水平扩展

水平扩展采用中间件mycat、如果在阿里云可以采用成熟度比较高的polar-X

中间件的核心就是计算层、存储层分离,把表的数据根据一定的规则,分散到不同的数据库不同的表中,让数据表保持很小的轻量级的运行。

 

2)离线统计业务

当数据上亿时,同时使用mysql做线上数据库,又做统计数据库就不适合了。

方案1:

同步数据,从库进行只读查询,单独的数据库做统计查询。

方案2:

当数据库再大的时候在mysql统计起来就非常吃力了,就需要把数据同步到hbase中

阿里云MaxCompute配合DataWorks,使用超级舒服,按量付费,成本极低。

     

 MaxCompute可以理解为开源的Hive,提供sql/mapreduce/ai算法/python脚本/shell 脚本等方式操作数据,数据以表格的形式展现,以分布式方式存储,采用定时任务和批处理的方式处理数据DataWorks提供了一种工作流的方式管理你的数据处理任务 和调度监控。

 

以上所有需要在具体业务中,应对变化,像修剪小树一样照顾应用系统。

 

千万级大表的优化是根据业务场景,以成本为代价进行优化的,绝对不是孤立的一个      层面的优化。