数据库分库分表主键策略:数据库优化四分表
数据库分库分表主键策略:数据库优化四分表一般在有严格的自增 id 需求上,按照 id 水平分表按区间范围分表比如:一个统计只提供按月查询的功能,那么把表按月拆分成12个,毎个查询只查询一个表就够了。如果是按照地域来分,即使把表拆的在小,查询还是要联合所有的表来查,还不如不拆;按时间分表这种方式有一定的局限性,当数据有较强的时效性,如微博发送记录、微信消息等等。这种数据很少有用户会查询几个月前的数据,
分表分表:【水平分表(行)】【垂直分表(列)】
水平分表
一张表的数据太多的时候要分表,如果一个表的记录数太多了,比如上千万条数据,而且需要经常检索,那我们就有必要优化一下;
如果拆成 100个表,那么每个表中的数据 就成了 10万条记录;
当然不可以胡乱拆分的,需要数据在逻辑上划分,一个好的划分有利于程序的简单实现,也可以充分利用水平分表的优势;
比如:一个统计只提供按月查询的功能,那么把表按月拆分成12个,毎个查询只查询一个表就够了。如果是按照地域来分,即使把表拆的在小,查询还是要联合所有的表来查,还不如不拆;
分表策略
按时间分表
这种方式有一定的局限性,当数据有较强的时效性,如微博发送记录、微信消息等等。这种数据很少有用户会查询几个月前的数据,
按区间范围分表
一般在有严格的自增 id 需求上,按照 id 水平分表
table1 id 从 1 ~ 100w
table2 id 从 100w ~ 200w
table3 id 从 200w ~ 300w
Hash 分表
通过一个原始目标的 ID 或者名称 通过一定的 HASH 算法计算出数据存储表的表名,然后访问相应的表;
最简单的 hash 算法: T_user Id0 1
垂直分表
有一些记录数并不多,可能也就几万条,但是表字段却很长,表占用空间很大,检索表时需要执行大量 I/O,严重降低了性能,这个时候需要把大的字段拆分到另一个表,并且该表与原表是一对一的关系(外键)
如果一张表某个字段,信息量大,但是我们很少查询,则可以考虑把这些字段,单独的放入到一张表中。如果硬是要查询,就是用跨表查询(join)
不同在于分表将大表分解成为很多个独立的实体表,而分区是将数据分段划分在多个位置存放,可以是同一块磁盘也可以在不同的机器。
分区后,表面上还是有一张表,但是数据散列到多个位置了,消费者读写的时候操作的还是大表名字,db 自动去组织分区的数据;
分区优势
- 与单个磁盘或文件系统分区相比,可以存储更多的数据
- 很容就能删除不用或者过时的数据
- 一些查询可以得到极大的优化,可以并发查询
- 涉及到 SUM() / COUNT() 等聚合函数时,可以并发进行
- IO 吞吐量更大
分区方式
Range(范围)
基于一个给定的连续空间,把数据分配到不同分区
CREATE TABLE employees (
id INT NOT NULL
name VARCHAR(30)
hired DATE NOT NULL DEFAULT '20201-12-27'
job VARCHAR(30) NOT NULL
dept_id INT NOT NULL
) engine myisam
partition BY RANGE (dept_id) (
partition p0 VALUES LESS THAN (6)
partition p1 VALUES LESS THAN (11)
PARTITION p2 VALUES LESS THAN (16)
partition p3 VALUES LESS THAN (21)
);
List(预定义列表)
类似Range分区,区别在 List 分区是基于枚举出的值列表分区,而Range分区是根据给定的连续区间范围区分
LIST分区通过使用“PARTITION BY LIST(expr)”来实现,其中“expr” 是某列值或一个基于某个列值、并返回一个整数值的表达式,然后通过“VALUES IN (value_list)”的方式来定义每个分区,其中“value_list”是一个通过逗号分隔的整数列表。
CREATE TABLE employees (
id INT NOT NULL
name VARCHAR(30)
hired DATE NOT NULL DEFAULT '20201-12-27'
job_code INT
store_id INT
)
PARTITION BY LIST(store_id)(
PARTITION pQY VALUES IN (3 5 6 17)
PARTITION pJN VALUES IN (1 10 11 19)
PARTITION pCH VALUES IN (4 12 14 18)
PARTITION pJJ VALUES IN (2 9 13 16)
PARTITION pGX VALUES IN ( 7 8 15 20)
);
Hash(哈希)
通过对表的一个或多个列的 Hash Key 进行计算,最后通过这个 Hash 码不同数值对应的数据区域进行分区。
主要用来分散热点读,确保数据在预先确定个数的分区中尽可能平均分布。
CREATE TABLE employees (
id INT NOT NULL
name VARCHAR(30)
hired DATE NOT NULL DEFAULT '20201-12-27'
job_code INT
store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4
线性哈希与常规哈希区别
常规:哈希使用的是求哈希函数值的模式,缺点在于分区增加时的重新计算
线性:线性哈希功能使用的是一个线性的 2 的幂(powers-of-two)运算法则
线性哈希分区的优点在于增加、删除、合并和拆分分区将变得更加快捷,有利于处理含有极其大量数据的表。它的缺点在于,与使用
常规HASH分区得到的数据分布相比,各个分区间数据的分布不大可能均衡。
Key(键值)
是对 Hash 模式的一种延伸,这里的 Hash Key 是 MySQL 系统产生的,Composite(复合模式)
CREATE TABLE employees (
id INT NOT NULL
name VARCHAR(30)
hired DATE NOT NULL DEFAULT '20201-12-27'
job VARCHAR(30) NOT NULL
dept_id INT NOT NULL
)
partition BY KEY (job)
PARTITIONS 3;
与key不同在于key的值可以为空,但是要注意:
1) 可以不指定值,默认以主键为准
2) 如果没主键,以唯一键为准
3) 如果没主键,以唯一键为准,唯一键必须非空
4) 无主无唯一,就必须手动指定