MySQL之分区

官网地址:https://dev.mysql.com/doc/refman/8.0/en/partitioning.html

假设现在有提条业务线,需要用到100张表,每张表里面有100w条数据,我们现在需要遍历这些数据,从中取出一条符合条件的记录,最坏情况,可能需要遍历100*100w,这数据量是多么庞大。这时候我们就需要对表进行拆分了:

  • 垂直拆分:可以按照业务线维护进行聚合,如按照订单表,用户表,商品表等多种业务维度进行聚合到一个DB
  • 水平拆分:将每张表里面的100w条记录进行水平拆分,如第1-10w条记录放入第一个文件,第10w-20w条记录放入第二个文件,第20w-30w放入第三个文件,等。后续要检索数据,只需要选择其中一个文件遍历10w次,不需要再遍历100w次了

分区类型

MySQL支持下面几种分区:

  • 范围分区
CREATE TABLE members (
    firstname VARCHAR(25) NOT NULL,
    lastname VARCHAR(25) NOT NULL,
    username VARCHAR(16) NOT NULL,
    email VARCHAR(35),
    joined DATE NOT NULL
)
PARTITION BY RANGE( YEAR(joined) ) (
    PARTITION p0 VALUES LESS THAN (1960),
    PARTITION p1 VALUES LESS THAN (1970),
    PARTITION p2 VALUES LESS THAN (1980),
    PARTITION p3 VALUES LESS THAN (1990),
    PARTITION p4 VALUES LESS THAN MAXVALUE
);

按照字段joined的值将表members分成5个文件,如果小于1960则数据进入p0文件,如果小于1970,则数据进入p1文件:
在这里插入图片描述

  • 列表分区
CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LIST(store_id) (
    PARTITION pNorth VALUES IN (3,5,6,9,17),
    PARTITION pEast VALUES IN (1,2,10,11,19,20),
    PARTITION pWest VALUES IN (4,12,13,14,18),
    PARTITION pCentral VALUES IN (7,8,15,16)
);

对store_id进行分区,当store_id 等于3,5,6,9,17中一个,则数据放入pNorth,当store_id等于1,2,10,11,19,20中一个,则数据放入pEast

  • 列分区
    范围分区和列表分区的综合,对分区列支持多种数据格式。

  • hash分区

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4;

针对store_id的hash值进行分区,PARTITIONS 4表明总共有4个分区。

  • key分区
CREATE TABLE k1 (
    id INT NOT NULL PRIMARY KEY,
    name VARCHAR(20)
)
PARTITION BY KEY()
PARTITIONS 2;

按照主键/唯一键进行分区,这种分区类似于hash分区,但是key的hash算法只能由系统指定。

  • 子分区
CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) )
    SUBPARTITIONS 2 (
        PARTITION p0 VALUES LESS THAN (1990),
        PARTITION p1 VALUES LESS THAN (2000),
        PARTITION p2 VALUES LESS THAN MAXVALUE
    );

子分区,是将分区表在进行分区,先根据purchased进行范围分区(p0,p1,p2),在每个分区内部,在按照purchased的hash进行分2个区:
在这里插入图片描述

工作过程

从上面我们可以看出,一个分区表室友是由多个相关的底层表(p0,p1,p2)实现的,我们可以直接访问各个分区表。所有的底层表都必须使用相同的存储引擎,从存储引擎的角度看,底层表和普通表没有什么不一样

select查询
​ 当查询一个分区表的时候,分区层先打开并锁住所有的底层表,优化器先判断是否可以过滤部分分区,然后再调用对应的存储引擎接口访问各个分区的数据

insert操作
​ 当写入一条记录的时候,分区层先打开并锁住所有的底层表,然后确定哪个分区接受这条记录,再将记录写入对应底层表

delete操作
​ 当删除一条记录时,分区层先打开并锁住所有的底层表,然后确定数据对应的分区,最后对相应底层表进行删除操作

update操作
​ 当更新一条记录时,分区层先打开并锁住所有的底层表,mysql先确定需要更新的记录再哪个分区,然后取出数据并更新,再判断更新后的数据应该再哪个分区,最后对底层表进行写入操作,并对源数据所在的底层表进行删除操作

虽然每个操作都会“先打开并锁住所有的底层表”,但这并不是说分区表在处理过程中是锁住全表的,如果存储引擎能够自己实现行级锁,例如innodb,则会在分区层释放对应表锁。

注意项

  1. null值会无法使用分区进行过滤,只能全表扫描
  2. 如果分区列和索引列不匹配,查询无法进行分区过滤,很好理解,如果列不一致,那查询时,优化器到底是应该用索引呢还是用分区呢?
  3. 如果分区的颗粒度很细,有可能会提高选择分区的成本
  4. 操作数据时,需要打开或者锁住底层表(表锁,或者行锁),维护的成本的可能会比较高
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值