第一段:分库分表的必要性
分库分表技术的使用,主要是数据库产生了瓶颈,如单库的并发访问或单表的查询都超出了阈值.对系统使用造成一定的影响,不得已而产生的技术.
通过分库分表技术来解决此类问题,但正因为使用此技术,会产生ACID一系列的问题,各类中间件解决此类问题各有各的优势.
提示:如场景无必要,千万不要使用分库分表.
第二段:分库分表的思路
①.、垂直区分
垂直分库:从业务角度,一个库分成多个库,如把订单和用户信息分成两个库来存储.这样的好处就是可以微服务了.每块的业务单独部署,互不影响,通过接口去调用.
垂直分表:把大表分成多个小表,如热点数据和非热点数据分开,提高查询速度.
水平分表:同一业务如数据量大了以后,根据一定的规则分为不同的表进行存储.
水平分库:如订单分成多个库存储,分解服务器压力.
以上一般来说,垂直分库和水平分表用的会多些.
第三段:分库分表的原理分析
分库分表常用的方案:Hash取模方案和range范围方案;
路由算法为最主要的算法,指得是把路由的Key按照指定的算法进行存放;
①.、Hash取模方案
根据取余分配到不同的表里.要根据实际情况确认模的大小.此方案由于平均分配,不存在热点问题,但数据迁移很复杂.
range根据范围进行划分,如日期,大小.此方案不存在数据迁移,但存在热点问题.
第四段:分库分表的技术选型
①.、技术选型
(1)mysql分区技术:把一张表存放在不同存储文件.由于无法负载,使用较少.
解决此类问题的中间件主要为:Proxy模式、Client模式.
(1)Proxy模式
由于Client模式少了一层,运维方便,相对来说容易些.
第五段:分库分表的实践
根据容量(当前容量和增长量)评估分库或分表个数 - 选key(均匀)- 分表规则(hash或range等)- 执行(一般双写)- 扩容问题(尽量减少数据的移动).
今天这一节我们选用中间件share-jdbc.
①.、引入maven依赖
行表达式标识符可以使用${...}或$-{...},但前者与Spring本身的属性文件占位符冲突,所以呢在Spring环境中使用行表达式标识符建议使用$-{...}.
通过ShardingDataSourceFactory工厂和规则配置对象获取ShardingDataSource,ShardingDataSource实现自JDBC的标准接口DataSource.然后即可通过DataSource选择使用原生JDBC开发,或者使用JPA, MyBatis等ORM工具.
基本思想之什么是分库分表?
从字面上简单理解,就是把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上.
基本思想之为什么要分库分表?
数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;另外,由于无法进行分布式式部署,而一台服务器的资源(cpu、磁盘、内存、io等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈.
分库分表的实施策略.
分库分表有垂直切分和水平切分两种.
何谓垂直切分,即将表按照功能模块、关系密切程度划分出来,部署到不同的库上.例如,我们会建立定义数据库workdb、商品数据库paydb、用户数据库userdb、日志数据库logdb等,分别用于存储项目数据定义表、商品定义表、用户数据表、日志数据表等.
何谓水平切分,当一个表中的数据量过大时,我们可以把该表的数据按照某种规则,例如userid散列,进行划分,然后存储到多个结构相同的表,和不同的库上.例如,我们的userdb中的用户数据表中,每一个表的数据量都很大,就可以把userdb切分为结构相同的多个userdb:part0db、part1db等,再将userdb上的用户数据表usertable,切分为很多usertable:usertable0、usertable1等,然后将这些表按照一定的规则存储到多个userdb上.
应该使用哪一种方式来实施数据库分库分表,这要看数据库中数据量的瓶颈所在,并综合项目的业务类型进行考虑.
如果数据库是因为表太多而造成海量数据,并且项目的各项业务逻辑划分清晰、低耦合,那么规则简单明了、容易实施的垂直切分必是首选.
而如果数据库中的表并不多,但单表的数据量很大、或数据热度很高,这种情况之下就应该选择水平切分,水平切分比垂直切分要复杂一些,它将原本逻辑上属于一体的数据进行了物理分割,除了在分割时要对分割的粒度做好评估,考虑数据平均和负载平均,后期也将对项目人员及应用程序产生额外的数据管理负担.
在现实项目中,往往是这两种情况兼而有之,这就需要做出权衡,甚至既需要垂直切分,又需要水平切分.我们的游戏项目便综合使用了垂直与水平切分,我们首先对数据库进行垂直切分,然后,再针对一部分表,通常是用户数据表,进行水平切分.
分库分表存在的问题.
事务问题.
在执行分库分表之后,由于数据存储到了不同的库上,数据库事务管理出现了困难.如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价;如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担.
跨库跨表的join问题.
在执行了分库分表之后,难以避免会将原本逻辑关联性很强的数据划分到不同的表、不同的库上,这时,表的关联操作将受到限制,我们无法join位于不同分库的表,也无法join分表粒度不同的表,结果原本一次查询能够完成的业务,可能需要多次查询才能完成.
额外的数据管理负担和数据运算压力.
额外的数据管理负担,最显而易见的就是数据的定位问题和数据的增删改查的重复执行问题,这些都可以通过应用程序解决,但必然引起额外的逻辑运算,例如,对于一个记录用户成绩的用户数据表usertable,业务要求查出成绩最好的100位,在进行分表之前,只需一个order
by语句就可以搞定,但是在进行分表之后,将需要n个order
by语句,分别查出每一个分表的前100名用户数据,然后再对这些数据进行合并计算,才能得出结果.
上述整理于互联网
分区介绍:
第一段:什么是分区?
所谓分区,就是将一个表分成多个区块进行操作和保存,从而降低每次操作的数据,提高性能.而对于应用来说则是透明的,从逻辑上看只有一张表,但在物理上这个表可能是由多个物理分区组成的,每个分区都是独立的对象,可以进行独立处理.
第二段:分区作用
①可以逻辑数据分割,分割数据能够有多个不同的物理文件路径.
第三段:分区能支持的引擎
第四段:确认MySQL支持分区
老版本用:SHOW VARIABLES LIKE '%partition%';
新版本用:show plugins;
第五段:分区类型
① RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区.
通过HASH运算来进行分区,分布的比较均匀
按照KEY进行分区类似于按照HASH分区
第六段:使用分区注意事项
① 如果表中存在primary key 或者 unique key 时,分区的列必须是paimary key或者unique key的一个组成部分,也就是说,分区函数的列只能从pk或者uk这些key中取子集
第七段:分区命名
① 分区的名字基本上遵循其他MySQL 标识符应当遵循的原则,例如用于表和数据库名字的标识符.应当注意的是,分区的名字是不区分大小写的.
第八段: 创建分区
① RANGE分区:
HASH分区主要用来确保数据在预先确定数目的分区中平均分布.在RANGE分区和LIST分区中必须明确指定一个指定的列值或列值集合以指定应该保存在哪个分区中.而在HASH分区中,MySQL会自动完成这些工作,要做的只是基于将要被哈希的列值指定一个表达式,以及指定被分区的表将要被分割成的分区数量,如:
注意:
(1) 由于每次插入、更新、删除一行,这个表达式都要计算一次,这意味着非常复杂的表达式可能会引起性能问题,尤其是在执行同时影响大量行的运算(例如批量插入)的时候.
线性HASH分区在"PARTITION BY"子句中添加"LINEAR"关键字.
线性HASH分区的有点在于增加、删除、合并和拆分分区将变得更加快捷,有利于处理含有及其大量数据的表.它的缺点在于各个分区间数据的分布不大可能均衡.
类似于HASH分区,HASH分区允许用户自定义的表达式,而KEY分区则不允许使用用户自定义的表达式;HASH分区只支持整数分区,KEY分区支持除了blob和text类型之外的其他数据类型分区.
与HASH分区不同,创建KEY分区表的时候,可以不指定分区键,默认会选择使用主键或唯一键作为分区键,没有主键或唯一键,就必须指定分区键.
解读:根据分区键来进行分区
子分区是分区表中,每个分区的再次分割,适合保存非常大量的数据.
子分区可以用于特别大的表,可以在多个磁盘间分配数据和索引.例如:
第九段:MySQL分区处理NULL值的方式
十、分区管理概述
可以对分区进行添加、删除、重新定义、合并或拆分等管理操作.
① RANGE和LIST分区的管理
① 删除分区语句如:alter table tbl_test drop partition p0;
(1) 当删除了一个分区,也同时删除了该分区中所有的数据.
(1) 对于RANGE分区的表,只可以添加新的分区到分区列表的最高端.
REORGANIZE会对分区的数据进行重构.
ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO(partition_definitions)
(1) 拆分分区如:
或者如:
② HASH和KEY分区的管理
③ 其他分区管理语句
十、查看分区信息
① 查看分区信息:select * from information_schema.partitions where table_schema='arch1' and table_name = 'tbl_test' G;
十第一段: 局限性
①.0. 分区字段尽量不要可以为null