mysql调优四-分区表

mysql调优四-分区表


前言

        本文介绍如何使用分区表对mysql进行优化。


一、分区表原理


        1、分区表构成:
        分区表是由多个相关的底层表实现的,可以直接访问各个分区。存储引擎管理分区的各个底层表和管理普通表一样(所有的底层表都必须使用相同的存储引擎),分区表的索引只是在各个底层表上各自加上一个完全相同的索引。

        2、分区表操作逻辑:
        SELECT:
        查询分区表时分区层打开并锁住所有的底层表,优化器先判断是否可以过滤部分分区,然后再调用对应的存储引擎接口访问各个分区的数据。
        INSERT:
        写入记录时分区层打开并锁住所有的底层表,先确定哪个分区接收这条记录,再将记录写入对应底层表。
        DELETE:
        删除记录时分区层打开并锁住所有的底层表,先确定数据对应的分区,再对相应底层表进行删除操作。
        UPDATE:
        更新记录时分区层打开并锁住所有的底层表,先确定需要更新的记录在哪个分区,取出数据并更新,再判断更新后的数据应该在哪个分区,最后对底层表进行写入操作,并对源数据所在的底层表进行删除操作。

        注:相关操作,如果where条件和分区表达式(即分区条件)匹配,那么就可以将不包含该条记录的分区全过滤掉,无需对任何其他分区进行操作。
        存储引擎如果是innodb,会在分区层释放对应的表锁,转成行锁(因为innodb可以实现行级锁)。

二、分区表类型

1.范围分区

        根据列值在给定范围内将对应行分配给对应分区。每个分区都包含行数据且分区的表达式在给定的范围内,分区的范围应该是连续的且不能重叠,可以使用values less than运算符来定义。

CREATE TABLE useremp (
    id INT NOT NULL,
    name VARCHAR(30),
    creat_date DATE NOT NULL DEFAULT '1970-01-01',
    code INT NOT NULL,
    user_id INT NOT NULL
)
-- 根据user_id创建四个分区,maxvalue表示始终大于等于最大可能整数值的整数值
PARTITION BY RANGE (user_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);
-- 根据creat_date创建分区(精确年)
PARTITION BY RANGE ( YEAR(create_date) ) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1996),
    PARTITION p2 VALUES LESS THAN (2001),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);
-- 根据creat_date创建分区(精确天)
PARTITION BY RANGE COLUMNS(create_date) (
    PARTITION p0 VALUES LESS THAN ('1960-01-01'),
    PARTITION p1 VALUES LESS THAN ('1970-01-01'),
    PARTITION p2 VALUES LESS THAN ('1980-01-01'),
    PARTITION p3 VALUES LESS THAN ('1990-01-01'),
    PARTITION p4 VALUES LESS THAN MAXVALUE
);

2、列表分区

        类似于范围分区,列表分区是基于列值匹配一个离散值集合中的某个值来进行选择分区的。

PARTITION BY LIST(user_id) (
    PARTITION p1 VALUES IN (3,5,6,9,17),
    PARTITION p2 VALUES IN (1,2,10,11,19,20),
    PARTITION p3 VALUES IN (4,12,13,14,18),
    PARTITION p4 VALUES IN (7,8,15,16)
);

3、列分区

        从5.5开始支持列分区,可以认为是范围分区和列表分区的升级版,列分区只接受普通列不接受表达式。

 CREATE TABLE test_list (
 col1 int(11) DEFAULT NULL,
 col2 int(11) DEFAULT NULL,
 col3 char(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
PARTITION BY RANGE COLUMNS(col1,col3)
(PARTITION p0 VALUES LESS THAN (10,'aaa') ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (20,'bbb') ENGINE = InnoDB);

4、哈希分区

        基于用户定义表达式的返回值来进行选择的分区,该表达式用将要插入到表中的这些行的列值进行计算。

CREATE TABLE useremp2 (
    id INT NOT NULL,
    name VARCHAR(30),
    code INT NOT NULL,
    creat_date DATE NOT NULL DEFAULT '1970-01-01',
    user_id INT NOT NULL
)
-- 对user_id取hash值%4产生四个分区
PARTITION BY HASH(user_id)
PARTITIONS 4;
-- 对creat_date的年份取hash值%4产生四个分区
PARTITION BY LINEAR HASH(YEAR(creat_date))
PARTITIONS 4;

5、key分区

        类似于哈希分区,区别为key分区支持一列或多列,且mysql服务器提供其自身的哈希函数,必须有一列或多列包含整数值。

6、子分区

        在分区的基础之上,再进行分区后存储。

CREATE TABLE test_table
(
  id INT AUTO_INCREMENT,
  name VARCHAR(10) NOT NULL,
  status INT(2) NOT NULL
  PRIMARY KEY (id, status)
)  ENGINE = INNODB
PARTITION BY RANGE(id)
SUBPARTITION BY HASH(status) SUBPARTITIONS 2
(
PARTITION p0 VALUES LESS THAN(5),
PARTITION p1 VALUES LESS THAN(10),
PARTITION p2 VALUES LESS THAN(15)
);

三、分区表限制

        1、一个表最多只能有1024个分区,5.7版本之后可以支持8196个分区。
        2、低版本时,分区表达式必须是整数或者是返回整数的表达式,5.5之后,可以直接使用列来进行分区。
        3、如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来。可以通过复合主键或者将主键索引改为普通索引的方式解决该问题。
        4、分区表无法使用外键约束。

四、分区表应用场景及优点

        优点:
        1、分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。
        2、分区表的数据更容易维护:批量删除大量数据可以使用清除整个分区的方式,对一个独立分区进行优化、检查、修复等操作。
        3、可以备份和恢复独立的分区。
        4、可以使用分区表来避免某些瓶颈:innodb的单个索引的互斥访问


        应用:
        1、表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他均是历史数据。
        表的数据量巨大时,肯定不能在每次查询的时候都扫描全表。因为索引在空间和维护上的消耗,也最好不要使用索引,即使使用索引,产生大量的碎片,还会产生大量的随机IO,在数据量巨大的时候,索引也无法起来明显作用了,此时可以使用分区表。
        使用简单的分区方式存放表,不要任何索引,根据分区规则大致定位需要的数据,通过使用where条件将需要的数据限制在少数分区中,这种方式适用于以正常的方式访问大量数据。
        如果数据有热点,除了热点数据其它数据很少被访问到,可以将这部分热点数据单独放在一个分区中,让这个分区的数据能够有机会都缓存在内存中,这样查询可以只访问一个小的分区表,能够使用索引,也能够有效的使用缓存。

五、注意的点

        1、null值会使分区过滤无效,分区条件的字段需要保证没有null值。
        2、分区列和索引列不匹配,会导致查询无法进行分区过滤。
        3、打开并锁住所有底层表的成本可能很高,需要考虑维护分区的成本。

总结

        在合适的场景下使用分区表,根据具体的业务场景来确定用来分区的列,在非必要情况下不使用分区表,因为要考虑维护成本等问题。

猜你喜欢

转载自blog.csdn.net/weixin_49442658/article/details/112576004