分库分表设计(千万级数据的解决方案)

分表设计:对于访问极为频繁且数据量巨大的单表来说,我们首先要做的就是减少单表的记录条数,以便减少数据查询所需要的时间,提高数据库的吞吐,这就是所谓的分表!

垂直拆分:

1.当一张表的字段过多时则可以考虑垂直拆分。

2.通常是将一张表的字段才分为主表以及扩展表,使用频次较高的字段在一张表,其余的在一张表,热点数据,冷数据分别放到不同的表里面,热点数据查询修改比较多。

3.有些字段类型很大,可以单独抽取出来(在我们项目中的每周总结markdown类型很大)

 

这里的多表查询也不建议使用 join ,依然建议使用两次查询。

例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。

垂直拆分的优点: 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。

垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决(不建议使用Join)。此外,垂直分区会让事务变得更加复杂;

水平拆分:

保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。

一般水平拆分是根据表中的某一字段(通常是主键 ID )取模处理(hash算法),将一张表的数据拆分到多个表中。这样每张表的表结构是相同的但是数据不同。

不但可以通过 ID 取模分表还可以通过时间分表,比如每月生成一张表。 按照范围分表也是可行的:一张表只存储 0~1000W的数据,超过只就进行分表,这样分表的优点是扩展灵活,但是存在热点数据。

按照取模分表拆分之后我们的查询、修改、删除也都是取模。比如新增一条数据的时候往往需要一张临时表来生成 ID,然后根据生成的 ID 取模计算出需要写入的是哪张表。

分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义。所以 水平拆分最好分库 ,这里就通过一致性hash算法来进行分库。

 

关于分区和分表的区别:

1,实现方式上 

mysql的分表是真正的分表,一张表分成很多表后,每一个小表都是完正的一张表,都对应三个文件(MyISAM引擎:一个.MYD数据文件,.MYI索引文件,.frm表结构文件)。

2,数据处理上 

分表后数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。分区则不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表还是一张表,数据处理还是由自己来完成。

3,提高性能上 

 分表后,单表的并发能力提高了,磁盘I/O性能也提高了。分区突破了磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql性能。 

在这一点上,分区和分表的测重点不同,分表重点是存取数据时,如何提高mysql并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql性能的目的。 

4,实现的难易度上 

分表的方法有很多,用merge来分表,是最简单的一种方式。这种方式和分区难易度差不多,并且对程序代码来说可以做到透明的。如果是用其他分表方式就比分区麻烦了。 分区实现是比较简单的,建立分区表,跟建平常的表没什么区别,并且对代码端来说是透明的。

 

问题:mysql有一亿数据,要全部取出,怎么弄?(用多个线程根据自增主键的范围取出)如果主键不自增,分配不均匀呢?

简单的建立索引,分表(可以按照时间,活跃度)

1.一亿数据我们可以通过hash一致性算法把这些数据分到不同的库里面,我们可以开多线程从不同的库里面取。

2.对于大量数据,我们一次也是无法读入内存的,我们通过分页批量查询,在查出数据之后把每次的数据按一定规则存入本地文件。

 

大量数据插入(在主从复制中可能出现):

一条一条插入(不行)

1.一次插入50000条数据(将这50000条数据组装成一个SQL文件),这是我最后选中的方案,一是能及时发现有问题的数据,二是导入数据非常稳定。就像支持断点续传一样,每一步都能看到效果。在执行脚本时,也能同步开始写分析逻辑;

2.组装成SQL文件,最后统一导入;组装一个大的SQL文件,最后通过MySQL自带的工具导入也是极好的。但如果有一条SQL有问题,你可能需要重跑一次脚本。

分库分表存在的问题

1 事务问题。

在执行分库分表之后,由于数据存储到了不同的库上,数据库事务管理出现了困难。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价;如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。

2 跨库跨表的join问题。

在执行了分库分表之后,难以避免会将原本逻辑关联性很强的数据划分到不同的表、不同的库上,这时,表的关联操作将受到限制,我们无法join位于不同分库的表,也无法join分表粒度不同的表,结果原本一次查询能够完成的业务,可能需要多次查询才能完成。

3 额外的数据管理负担和数据运算压力。

额外的数据管理负担,最显而易见的就是数据的定位问题和数据的增删改查的重复执行问题,这些都可以通过应用程序解决,但必然引起额外的逻辑运算,例如,对于一个记录用户成绩的用户数据表userTable,业务要求查出成绩最好的100位,在进行分表之前,只需一个order by语句就可以搞定,但是在进行分表之后,将需要n个order by语句,分别查出每一个分表的前100名用户数据,然后再对这些数据进行合并计算,才能得出结果。

 

拆分以后的问题就是两段提交,事务如何保证:

待解决。

需要学习:

https://segmentfault.com/a/1190000006158186

posted @ 2019-03-27 17:24  LeeJuly  阅读(1630)  评论(0编辑  收藏  举报