随着互联网的发展潮流,慢慢衍射出需要大数据存储的场景;而且在各行各业中大数据存储场景越来越常见;在面对大数据的读取过程中我们往往会考虑到ES、Redis等非关系型数据库的使用;这些技术的引入的确解决了数据读取问题,然而这些数据也需要在关系型数据库中存储,那么如何有效解决这一问题呢?本文拿mysql为例来阐述对于大数据存储方面的一些方案;
一,分表场景
对于Mysql而言在面对大数据存储的场景中若数据量超过一定量(一般参考500W)之后就要考虑分库或者分表方式来建立关系型数据库;(如果数据量特别大,可以考虑分库方案,本文只考虑分表方案);
二,分表类型
Mysql常用分表策略有:垂直拆分(纵向拆分)和水平拆分(横向拆分)
所谓垂直拆分就是将一个大表拆分成:1:1 的一些小表;它们的拆分原则往往是依据业务不同,即“一失一的”,这样分的目的是减少单个表的存储空间;表与表之间通过业务外键关联;这样拆分不会减少单表的数据量但是可以提升对标的操作性能;
所谓水平拆分是将一个大表拆分成一系列小表;这些表之间是完全并列的关系;各个表之间的结构完全一致;(本文主要讨论水平分表方案)
三,水平分表的方法
水平分表有些数据库中间件可以很方便实现此功能如mycat;但是通过mycat官方指出采用mycat方式来进行分表,因为内部可能考虑复杂情形的联合查询等情况因此性能会降低10%-30%对于性能不是很强劲的mysql来说这些损失也是挺可惜的;因此业界普遍采用路由表方式来进行“手动”维护分表;目前分表一般采用如下几种:1)Hash、取模;2)时间;3)区间;4)路由表;
- 所谓的分表方式均只有一个目标即如何确认数据的存放位置。即通过如上算法确定表序号;
3.1Hash、取模
该方法是对操作的数据主键进行hash取模追踪取到对应的表序号;
该算法的核心是找到表的下标,若id为字符串则可以对id进行hash最终取模得到一个下标;如对一个新闻表采用分表方式存储,若拆分为10个表,若需要插入id为20001的数据则该条数据需要存到下标为1的表中(news_1);
按照id对该表进行读取同样需要计算该id所对应的数据存在于哪个表中;
3.2时间
该方法对于日志数据较为普遍,譬如对于大量日志数据的存储则可以按照时间格式命名表的后缀;如同样对于新闻表采用按照时间方式分表(如一个月一张表)可以采用new_202105的方式进行。如果我们需要存储创建时间在2021年五月的数据则存放在后缀为202105的表中;
读取同样需要指明当前数据存放在哪个时间段内;
3.3区间
该方法可以将各个表内的数据均匀分配;譬如规定好每个表中的数据10000000(1KW)则可以根据id计算出当前数据所在的数据表;如id范围为:【1——10000000】存在于new_1中;【10000001-20000000】存在于new_2中。这样分表的优点在于容易计算表的后缀:(id/10000000+1)但是若对于id不为数字类型则实现起来有困难;
3.4路由表
该方法是最灵活的实现方式;对于各个分表内部存放的数据范围有明确的标识,我们需要新建一个路由表来存放如上数据;
+-----------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | root_table_name | varchar(64) | NO | | NULL | | | table_name | varchar(64) | NO | | NULL | | | min_id | int(11) | NO | | NULL | | | max_id | int(11) | NO | | NULL | | +-----------------+-------------+------+-----+---------+----------------+
对于操作一条数据可以通过该表查询本数据所在的分表名称;
这样做的优点很明显:
1)可以灵活控制每个分表的数据量;
2)扩展表或者调整每个分表的数据很方便;
+----+-----------------+------------+----------+----------+ | id | root_table_name | table_name | min_id | max_id | +----+-----------------+------------+----------+----------+ | 2 | document | document_1 | 12000001 | 35000000 | +----+-----------------+------------+----------+----------+
如定义id范围在:【12000001-35000000】之间的数据存在于document_1中;