原文链接:http://www.cnblogs.com/dinglang/p/6084306.html
1.垂直分表
垂直分表在日常开发和设计中比较常见,通俗的说法叫做“大表拆小表”,拆分是基于关系型数据库中的“列”(字段)进行的。通常情况下,某个表中的字段比较多,可以新建一张“扩展表”,将不经常使用或者长度较大的字段拆分出去放到“扩展表”中。
拆分字段的操作建议在数据库设计阶段就做好。如果是在发展过程中拆分,则需要改写以前的查询语句,会额外带来一定的成本和风险,建议谨慎。
2.垂直分库
垂直分库在“微服务”盛行的今天已经非常普及了。基本的思路就是按照业务模块来划分出不同的数据库,而不是像早期一样将所有的数据表都放到同一个数据库中。
在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈,是大型分布式系统中优化数据库架构的重要手段。
3.水平分表
水平分表也称为横向分表,比较容易理解,就是将表中不同的数据行按照一定规律分布到不同的数据库表中(这些表保存在同一个数据库中),这样来降低单表数据量,优化查询性能。最常见的方式就是通过主键或者时间等字段进行Hash和取模后拆分。
水平分表,能够降低单表的数据量,一定程度上可以缓解查询性能瓶颈。但本质上这些表还保存在同一个库中,所以库级别还是会有IO瓶颈。所以,一般不建议采用这种做法。
4.水平分库分表
水平分库分表与上面讲到的水平分表的思想相同,唯一不同的就是将这些拆分出来的表保存在不同的数据中。这也是很多大型互联网公司所选择的做法。
某种意义上来讲,有些系统中使用的“冷热数据分离”(将一些使用较少的历史数据迁移到其他的数据库中。而在业务功能上,通常默认只提供热点数据的查询),也是类似的实践。在高并发和海量数据的场景下,分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源的瓶颈。当然,投入的硬件成本也会更高。同时,这也会带来一些复杂的技术问题和挑战(例如:跨分片的复杂查询,跨分片事务等)
5.分库分表的遇到的问题
(1).跨库join的问题:
基于架构规范,性能,安全性等方面考虑,一般是禁止跨库join的。那该怎么办呢?
A.全局表
所谓全局表,就是系统中所有模块都可能会依赖到的一些表。比较类似我们理解的“数据字典”。为了避免跨库join查询,我们可以将这类表在其他每个数据库中均保存一份。
B.字段冗余
“订单表”中保存“卖家Id”的同时,将卖家的“Name”字段也冗余,这样查询订单详情的时候就不需要再去查询“卖家用户表”。字段冗余能带来便利,是一种“空间换时间”的体现。
C.系统层组装
在系统层面,通过调用不同模块的组件或者服务,获取到数据并进行字段拼装。eg : 分两次查询实现,在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据,最后将查询数据组装。
(2).跨库事务(分布式事务)的问题:
两阶段提交(2PC) | 补偿事务(TCC) | 本地消息表(异步确保)
https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html
(3).分布式全局唯一ID
在分库分表的环境中,数据分布在不同的分片上,不能再借助数据库自增长特性直接生成,否则会造成不同分片上的数据表主键会重复。以下几种ID生成算法可解决这个问题:
- Twitter的Snowflake(又名“雪花算法”) https://segmentfault.com/a/1190000011282426
- UUID/GUID(一般应用程序和数据库均支持)
- MongoDB ObjectID(类似UUID的方式) https://www.cnblogs.com/weilunhui/p/6861938.html
- Ticket Server(数据库生存方式,Flickr采用的就是这种方式)