关系型数据库本身比较容易成为系统性能的瓶颈,虽然读写分离能分散数据库的读写压力,但并没有分散存储压力,当数据量达到千万甚至上亿时,单台数据库服务器的存储能力会成为系统的瓶颈,主要体现在以下几个方面:
因此,当并发量越来越大、且单机容量达到上限时,往往需要分库分表,减轻单机数据库的存储压力、读写压力,由多台数据库服务器一起分担压力,提高数据库性能。
有2种切分策略:水平切分、垂直(纵向)切分。
在字段很多的情况下,通过大表拆小表,更方便开发、维护,也能避免跨页问题。
mysql底层是通过数据页存储数据的,一条记录占用空间过大会导致跨页,造成额外的开销。
另外,数据库以行为单位将数据加载到内存中,表中字段长度越短且访问频次较高,内存能加载更多的数据、命中率更高(缓存),减少磁盘IO,从而提升数据库性能。
当难以再进行细粒度的垂直切分来提升性能、或单表的记录数巨大,这时可以进行水平切分。
按拆分出来的表的存放位置来分,水平切分可分为2种:
(1)库内分表 将一个表的记录拆分为多个表,每个表中只包含部分记录,使得单表的记录数变少,拆分出来的表放在同一数据库中
(2)分库分表 拆分出来的表放在不同不同的数据库中
库内分表只解决了单一表记录数过大的问题,但没有将表分布到不同的库(机器)上,拆分出来的表还是竞争同一个机器的CPU、内存、网络IO,对于减轻数据库存储压力来说帮助不是很大,水平切分最好选择分库分表。
水分切分是以记录为单位进行拆分。
水平切分后原本一张表的记录会分散到一个数据库或多个数据库的多张表中,操作数据库时怎么知道哪条记录在哪个库里的哪个表里?水平切分需要配置路由。
水平切分按记录切分方式可分为2种:
优、缺点
选取某个列或几个列的值进行hash运算,根据得到的hash值来划分记录到到不同的表。
比如以id列进行hash运算,拆分为10个表,计算(id % 10)的hash值,余数为0的都划到第一个表中,为1的都划到第二个表中.....为9的划到第10个表中,不推荐使用这种方式,查询起来不方便。
比如以商品信息表以商品类型(有限个数的常量)这一列计算hash值,把同一商品类型的所有商品记录划到一个表中,eg.手机类商品划到一个表中,电脑类商品划到一个表中,智能穿戴类商品划到一个表中.....
这种方式的关键在于初始表数量的选取上,表数量太多维护起来很麻烦,表数量太小又解决不了单表性能存在问题。
水平分表的关键在于子表数量的选取。
优缺点与范围划分的刚好相反:
新建一张数据表作为路由表,一列存储划分出来的表的表名,
如果是以范围划分的,min_index、max_index2列分别存储该表的范围,比如[1,9999999];如果是以有限的常量来划分的,则用一列来存储该表对应的常量,比如存储商品类型。
水平分表,扩充表的时候,需要修改路由表;
操作数据库的时候,需要先查询路由表得到记录所在的表,要多查询一次,会影响性能,所以除非单表的记录数真的很多,否则不要轻易水平分表。
就算要水平分表,子表数量也不宜太多,一个是难以维护,另一个是字表太多会导致路由表中的记录数很多,查询路由表的时间开销会变大;如果路由表记录数很多,再将路由表分库分表,则又面临一个死循环。
垂直切分,表的结构一旦设计好,一般不会变化,比如将tb_user垂直划分为3个表,列一般不会增减,就算增加列,也是加在业务相关性大的子表中,代码修改幅度不大,我们可以直接在代码中写死拆分出来的子表名,不必使用路由表。
水平切分,记录数是经常变化的,经常要扩容,子表数量往往要增加,不能在代码中写死子表名,要使用路由表做中间人。
分表后,原本一张表中的记录分散到多张表中,很多时候需要多表连接查询,连接其他表是要花时间的;尤其是分库导致要跨库查询时,连接另一个数据库中的表,很花时间,效率低。
聚合函数、order by排序、group by分组使用起来也不是很方便,都要从多个子表中查数据,然后汇总。
分库分表,效率有提升的地方,也有拉低的地方;
分库分表主要是为了减轻单机数据库的存储压力,效率还再其次。
原文:https://www.cnblogs.com/chy18883701161/p/12570269.html