1.2 数据库分区,从学习到放弃
先讲一下数据库的分区功能。分区并不是生成新的数据表,而是将表的数据均衡分配到不同的硬盘、系统或不同的服务器存储介质中,实际上还是一张表。
比如,要创建以下数据库表:
那么,数据库就会把这个t2表的数据根据YEAR(dob)这个表达式的值分布存储在d0~d7这8个分区。
数据库分区有以下优点。
1)比起单个文件系统或硬盘,分区可以存储更多的数据。
2)在清理数据时,可以直接删除废弃数据所在的分区。同样,有新数据时,可以增加更多的分区来存储新数据。
3)可以大幅度地优化特定的查询,让这些查询语句只去扫描特定分区的数据。比如,原来有2000万的数据,设计10个分区,每个分区存200万的数据,那么可以优化查询语句,让它只去查询其中两个分区,即只需要扫描400万的数据。
第3个优点正好可以解决此处的项目需求。但是,要怎么设计分区字段?也就是说,要根据什么来分区?
下面具体说一下该业务场景中的数据表。工单表ticket中的关键字段见表1-1。
表1-1 工单表关键字段
工单表最主要的几个查询语句如下。
1)客服查询无处理人的工单:“Where assignedUserID=?”。
2)客服获取分派给自己的工单:“Where status in(…)and assignedUserID=?”。
3)客服组长查看自己组的工单:“Where assignedUserGroupID=?”。
4)客服查询特定客户的工单:“Where consumerEmail=?”。
为了达到只扫描特定分区的效果,必须在Where语句里面加上一个包含分区字段的条件,但是上面这些主要语句并不包含相同的字段。
另外,MySQL的分区还有个限制,即分区字段必须是唯一索引(主键也是唯一索引)的一部分。工单表是用ticketID当主键,也就是说接下来无论使用什么当分区字段,都必须把它加到主键当中,形成复合主键。MySQL官方文档原文如下。
All columns used in the partitioning expression for a partitioned table must be part of every unique key that the table may have.
In other words,every unique key on the table must use every column in the table's partitioning expression(This also includes the table's primary key, since it is by definition a unique key.This particular case is discussed later in this section).
接着深入分析一下业务流程。
1)系统从邮件服务器同步到邮件以后,创建一个工单,createdTime就是工单创建的时间。
2)客服先去查询无处理人的工单,然后把工单分派给自己。
3)客服处理工单,每处理一次,系统自动增加一条处理记录。
4)客服处理完工单以后,将工单状态改为“关闭”。
通过跟客服的交流,项目组发现,一般工单被关闭以后,客服查询的概率就很低了。对于那些关闭超过一个月的工单,基本上一年都打开不了几次。
调研到这里,基本的思路是增加一个状态:归档。首先将关闭超过一个月以上的工单自动转为“归档”状态,然后将数据库分为两个区,所有“归档”状态的工单存放在一个区,所有非“归档”状态的工单存放在另外一个区,最后在所有的查询语句中加一个条件,就是状态不等于“归档”。
简单估算一下:客服频繁操作的工单基本上都是1个月内的工单,按照后期一天10万来算,也就是300万的数据,这样数据库的非归档区基本就没什么压力了。
那么,是否就将status设为分区字段,然后直接使用MySQL的分区功能?不是的。
因为相关的开发人员并没有用过数据库分区的功能,而当时面临的情况是只有1周的时间来解决问题,并且工单表是系统最核心的数据表,不能出问题。
这种情况下,没人敢在生产的核心功能上使用一项没用过的技术,但是项目组评估了一下,要实现一个类似的方案,其实工作量并不大,而且代码可控。因此,项目组放弃了数据库分区,并决定基于同样的分区理念,使用自己熟悉的技术来实现这个功能。
这个思路也很简单:新建一个数据库,然后将1个月前已经完结的工单数据都移动到这个新的数据库。这个数据库就叫冷库,因为里面基本是冷数据(当然,叫作归档数据库也可以),之后极少被访问。当前的数据库保留正常处理的较新的工单数据,这是热库。
这样处理后,因为客服查询的基本是近期常用的数据,大概只有300万条,性能就基本没问题了。即使因为查询频繁,或者几个客服同时查询,也不会再像之前那样出现数据库占满CPU、整个系统几乎宕机的情况了。
上面这个方法,其实就是软件系统常用的“冷热分离”。接下来介绍一下冷热分离的方案。