分表与分库
Posted ouhaitao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分表与分库相关的知识,希望对你有一定的参考价值。
前言
当我们的数据量逐渐膨胀,一张表的数据量变得非常巨大以致于影响性能时,我们需要一种手段来将表拆分成若干表以提高性能,这就是分表。当我们的数据量继续膨胀,我们单机数据库中已经存在非常多的子表,并且数据库服务器承受不了这样大量的请求时,我们需要一种手段将单机数据库的压力分摊到若干数据库,这就是分库。
一、简介
分表:将一张表按照一定的规则划分成若干分表,查询分表时可按照规则直接定位到一张分表,提高查询效率。
分库:分表之后,一个数据库中会产生非常多的表,数据库中的表过多会影响数据库的性能,并且数据量大了之后一台服务器是无法满足应用的需求,所以需要按照一定规则划分将数据库,将符合规则的表迁移至对于数据库。
分库分表可分为水平拆分和垂直拆分,水平拆分是按行拆分,将不同行放在不同表中;垂直拆分是按列拆分,将不同列放在不同表中。可以发现分区与分表相似。其实他们的思想相似,但是实际应用的场景不同导致了其实现不同。
ps:数据库表数量过多影响数据库性能的原因如下:
table_definition_cache是表定义信息缓存,用来存放表定义信息.当我们的mysql中使用了较多的表的时候,缓存需要频繁的切换影响性能.注意,这里设置的是可以缓存的表定义信息的数目,而不是内存空间的大小.
table_open_cache是打开表的缓存数量,不是定义内存的大小,而是定义可以缓存多少打开的表的文件句柄信息.如果定义的太小,那么MySQL在需要打开新表的时候就要不断的关闭已经打开的表和打开此次需要打开的表,性能会受到影响.
二、方式
1. 垂直分表
也就是“大表拆小表”,基于列字段进行的。一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到“扩展表“。一般是针对那种几百列的大表,也避免查询时,数据量太大造成的“跨页”问题。在数据量继续膨胀之后,依然会带来单表数据量过大影响性能问题。
2. 垂直分库
垂直分库针对的是一个系统中的不同业务进行拆分,拆分之后可以将数据库放在不同的服务器上,以获得更高的处理能力。垂直拆分在一定程度上可以提升硬件资源带来的瓶颈,这种实现方式简单,架构复杂度不高,但是如果数据继续膨胀,导致数据库中表增多,依然会导致性能下降。
3. 水平分表
针对数据量巨大的单张表(比如订单表),按照某种规则,切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。
4. 水平分库
针对于数据量巨大的数据库,按照某种规则,切分为多个数据库,切分后的数据库结构一样,放在不同的服务器上,数据根据切分的规则存入对于的数据库,获得了更多的硬件资源。
三、分库分表的一般思路
分库分表最重要的是拆分键的选择,当我们使用拆分键进行查询时,可以快速定位到对应的数据表,优秀的拆分键可以让查询效率大幅度提升,而差的分区键会导致查询效率反而下降。
1. 单拆分键
顾名思义,分库分表按照一个键进行拆分,但是有时候我们不使用拆分键进行查找的时候,会将所有表进行扫描,效率低下。有两种解决方案:冗余全量表和冗余关系表。
冗余全量表
例如将一张订单表t_order拆分成三张表t_order、t_user_order、t_merchant_order。分别使用三个独立的sharding column,即order_id,user_id,merchant_code。每一张表都是全量数据,数据同步可以使用binlog。
冗余关系表
只有一张表是全量表,其他表是关系表,例如将一张订单表t_order拆分成三张表t_order、t_user_order、t_merchant_order,t_order存储全量数据,order_id作为拆分键,t_user_order存储user_id和order_id,把user_id作为拆分键。
冗余全量表 VS 冗余关系表
速度对比:冗余全量表速度更快,冗余关系表需要二次查询,即使有引入缓存,还是多一次网络开销;
存储成本:冗余全量表需要几倍于冗余关系表的存储成本;
维护代价:冗余全量表维护代价更大,涉及到数据变更时,多张表都要进行修改。
2. 多拆分键
比如登录功能,需要使用用户名和密码登陆,这是把用户名和密码设为拆分键。
3. 拆分键+ES
上面提到的都是条件中有拆分键的SQL执行。但是,总有一些查询条件是不包含拆分键的,同时,我们也不可能为了这些请求量并不高的查询,无限制的冗余分库分表。那么这些查询条件中没有拆分键的SQL怎么处理?以sharding-jdbc为例,有多少个分库分表,就要并发路由到多少个分库分表中执行,然后对结果进行合并。这种条件查询相对于有拆分键的条件查询性能很明显会下降很多。
更有甚者,尤其是有些运营系统中的模糊条件查询,或者上十个条件筛选。例如淘宝我的所有订单页面,筛选条件有多个,且商品标题可以模糊匹配,这即使是单表都解决不了的问题,更不用谈分库分表了。
拆分键+ES的模式,将分库分表所有数据全量冗余到es中,将那些复杂的查询交给es处理。
四、分库分表带来的问题
1. 事务问题
在分库分表之后,数据存储在了不同的库上,所以本地事务失效,需要使用分布式事务解决,如果使用数据库的分布式事务支持则其效率相当低下,如果由程序控制则会存在编程上的负担并且会侵入到业务逻辑代码。
2. join问题
数据分散在了不同库上之后,join查询变得不可用,原本一次查询就可以做的事情,最后需要多次查询才能够完成。
3. 数据库额外的负担
在我们执行group by,order by,limit等等操作时,需要所有数据库节点同时执行并且最后还要聚合所有结果,会造成额外的负担。
五、什么时候使用分库分表
分库分表不是最优解,反而应该是最后的解决方案。分库分表会带来相当复杂的架构以及相当大的开发、维护成本,并且如果说架构设计出现问题,其带来的问题是巨大的。只有在所有方法都不能解决性能问题时再采用分库分表,一般可以考虑的优化包括:
设置远程数据库。如果使用的是一个整体应用程序,其中所有组件都位于同一个服务器上,那么可以通过将数据库移到它自己的机器上来提高数据库的性能。由于数据库的表保持不变,因此这不会增加分片的复杂性。
实现缓存。如果应用程序的读取性能较低,那么缓存是一种可以优化这个问题。缓存涉及临时存储已在内存中请求的数据,以后可以快速的从缓存访问。
读写分离。另一种有助于提高读取性能的策略,包括将数据从一个数据库服务器(主服务器)复制到一个或多个从服务器。在此之后,每次新的写操作在复制到从服务器之前都要先到主服务器,而读操作只对从服务器进行。像这样分发读写可以防止任何一台机器承担过多的负载,从而有助于防止速度下降和崩溃。请注意,创建读副本需要更多的服务器资源,因此花费更多的钱,这对一些人来说可能是一个很大的限制。
升级到更大的服务器。在大多数情况下,将一个数据库服务器扩展到具有更多资源的计算机比分片需要更少的工作量。与读写分离一样,具有更多资源的服务器升级可能会花费更多的钱。
以上是关于分表与分库的主要内容,如果未能解决你的问题,请参考以下文章