一、分区的优点
- 提高查询性能:当查询条件涉及分区键时,数据库可以只扫描相关分区,而不是整个表。
- 管理方便:可以单独对某个分区进行维护,比如删除旧数据时可以直接删除整个分区,效率更高。
二、基本分区类型
2.1 RANGE 分区(最常用)
根据一个给定连续区间的列值,将数据分配到不同的分区。通常用于日期或时间相关的列。
- 原理:为每个分区定义一個范围,当插入的数据的分区列值落入某个范围时,就被存储到对应的分区。
- 常见场景 :按年、按月分区日志表或交易记录表。可以很方便地删除旧数据(直接
DROP PARTITION
)。 - 示例:
sql
CREATE TABLE sales (
order_date DATE,
amount DECIMAL(10, 2)
)
PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p_2020 VALUES LESS THAN (2021),
PARTITION p_2021 VALUES LESS THAN (2022),
PARTITION p_2022 VALUES LESS THAN (2023),
PARTITION p_max VALUES LESS THAN MAXVALUE -- 用于存储未来所有超出定义范围的数据
);
-
表结构定义:
order_date DATE
:定义一个名为order_date
的日期类型的列。amount DECIMAL(10, 2)
:定义一个名为amount
的十进制数字列,总位数为10,小数点后保留2位。 -
分区方式:
PARTITION BY RANGE (YEAR(order_date))
:表示按照order_date
列的年份范围进行分区。YEAR(order_date)
会提取日期中的年份,然后根据年份的范围来划分数据存储的不同区域。 分区语句是使用RANGE分区,并且分区表达式是YEAR(order_date)。这里的分区条件是用LESS THAN来定义的。对于RANGE分区,每个分区的定义是使用VALUES LESS THAN (value)
来指定一个上限。分区的范围是从最低值开始,到指定的value为止,但不包括value。注意:value必须是一个常量表达式,且通常为整数或日期类型(取决于分区键的数据类型)。最后一个分区使用了MAXVALUE
,这是一个特殊的值,表示所有大于之前分区上限的值都会存储在这个分区中。分区键
可以是表达式,也可以是单个列。但是,在分区表达式中使用的列必须是表的主键的一部分,或者唯一索引(如果表有唯一索引)必须包含分区表达式中所有的列。具体规则如下: 如果表有主键,则分区键必须是主键的一部分。 如果表有唯一索引,则分区键必须是唯一索引的一部分。
2.2 List 分区
类似于 RANGE 分区,但分区是基于一个离散
的、不连续
的值的列表。
- 原理:为每个分区定义一個值列表,当插入的数据的分区列值等于列表中的任何一个值时,就被存储到对应的分区。
- 常见场景:按地区、按类别等离散值分区。例如,根据国家或状态代码分区。
- 示例:
sql
CREATE TABLE employees (
id INT,
name VARCHAR(100),
region_code INT
)
PARTITION BY LIST (region_code) (
PARTITION p_north VALUES IN (1, 2, 3), -- 区域代码为 1,2,3 的放在北部分区
PARTITION p_south VALUES IN (4, 5, 6),
PARTITION p_west VALUES IN (7, 8, 9),
PARTITION p_other VALUES IN (DEFAULT) -- 存储不在上述列表中的值
);
- 表结构定义:
CREATE TABLE employees (
: 创建一个名为employees
的表。id INT,
: 定义了一个整数类型的列id
,用于存储员工的ID。name VARCHAR(100),
: 定义了一个可变字符串类型的列name
,最大长度为100个字符,用于存储员工的姓名。region_code INT
: 定义了一个整数类型的列region_code
,用于存储区域代码。) PARTITION BY LIST (region_code) (
: 指定按照region_code
列进行列表分区。列表分区是根据某个列的离散值来划分分区,每个分区包含一组指定的值。PARTITION p_north VALUES IN (1, 2, 3),
: 创建一个名为p_north
的分区,用于存储region_code
值为1、2、3的数据。这些数据代表北部分区。PARTITION p_south VALUES IN (4, 5, 6),
: 创建一个名为p_south
的分区,用于存储region_code
值为4、5、6的数据。这些数据代表南部分区。PARTITION p_west VALUES IN (7, 8, 9),
: 创建一个名为p_west
的分区,用于存储region_code
值为7、8、9的数据。这些数据代表西部分区。PARTITION p_other VALUES IN (DEFAULT)
: 创建一个名为p_other
的分区,用于存储region_code
不在上述列表中的任何值。DEFAULT
关键字表示所有未在前面分区中指定的值都会存储在这个分区中。
- 总结: 该表根据
region_code
列的值将数据分布到四个不同的分区中。每个分区对应一个区域(北、南、西和其他)。这种分区方式可以优化查询性能,特别是当查询条件涉及region_code
时,数据库可以只扫描相关的分区,提高查询效率。同时,分区也有助于数据的管理和维护,比如可以独立备份或维护某个分区 - 列表分区的特点:
列表分区
(LIST Partitioning)是一种数据库分区策略,它根据某个列的离散值(即不连续的值,如类别、状态码、地区代码等)来划分数据。每个分区会包含一组指定的值,当插入数据时,数据库会根据这个列的值决定将数据放入哪个分区。
2.3 KEY 分区
类似于 HASH 分区,但 MySQL 使用服务器自身的哈希函数(基于 PASSWORD()
函数相同的算法)。KEY 分区只支持一列或多列(而 HASH 分区支持表达式)
- 原理:如果表有主键,但主键不适用于 RANGE 或 LIST 分区,KEY 分区是一个很好的选择,因为它通常使用主键作为分区键。
- 与 HASH 的区别:KEY 分区使用 MySQL 内置的哈希算法,而 HASH 分区使用用户指定的表达式。
- 如何选择KEY分区的分区键? : 如果表有主键 :通常可以选择主键的一部分或全部作为分区键。注意,如果表有主键,则分区键必须是主键的一部分或全部。也就是说,分区键必须是主键或唯一索引的一部分(除非没有主键或唯一索引)。 如果表没有主键:可以选择任何列作为分区键,但最好选择那些在查询中经常使用的列,且该列的值分布均匀。
- 示例:
sql
CREATE TABLE log_messages (
id INT AUTO_INCREMENT PRIMARY KEY,
message TEXT
)
PARTITION BY KEY (id) -- 使用主键 id 作为分区键
PARTITIONS 2;
- 分区部分:
PARTITION BY KEY (id)
:表示按照键进行分区。KEY分区是MySQL中一种分区类型,它使用哈希函数对分区键进行计算,从而确定数据行应该放在哪个分区。这里的分区键是主键id
。PARTITIONS 2
:表示创建2个分区。分区数可以自己指定。在创建表时,你可以通过PARTITIONS n
来指定分区的数量,其中n
是一个正整数。这个n
值可以根据你的需求来设定,但是通常需要考虑数据的分布、查询性能以及管理便利性等因素。 在KEY分区和HASH分区中,分区的数量是由用户指定的。而在RANGE
分区和LIST
分区中,分区的数量是由你定义的分区范围或列表值决定的,不需要指定分区数量,而是直接列出每个分区。例如,在KEY分区中,你可以指定任意数量的分区(只要在MySQL限制范围内,通常最大为1024
个分区,但实际可能受操作系统和存储引擎的限制)
- 实际效果:
- 表在物理上会被分成两个独立的文件(每个分区对应一个文件),但逻辑上仍然是一个表。
- 查询时,如果条件中包含
分区键(id)
,MySQL可以只扫描一个分区(分区修剪),从而提高查询效率。
- 示例:
- 表在物理上会被分成两个独立的文件(每个分区对应一个文件),但逻辑上仍然是一个表。
- 查询时,如果条件中包含
分区键(id)
,MySQL可以只扫描一个分区(分区修剪),从而提高查询效率。
- 总结: 该表根据
region_code
列的值将数据分布到四个不同的分区中。每个分区对应一个区域(北、南、西和其他)。这种分区方式可以优化查询性能,特别是当查询条件涉及region_code
时,数据库可以只扫描相关的分区,提高查询效率。同时,分区也有助于数据的管理和维护,比如可以独立备份或维护某个分区 - 列表分区的特点:
列表分区
(LIST Partitioning)是一种数据库分区策略,它根据某个列的离散值(即不连续的值,如类别、状态码、地区代码等)来划分数据。每个分区会包含一组指定的值,当插入数据时,数据库会根据这个列的值决定将数据放入哪个分区。
2.4 COLUMNS 分区(RANGE COLUMNS 和 LIST COLUMNS)
这是对标准 RANGE 和 LIST 分区的扩展,提供了更强大的功能。
- 原理 :
RANGE COLUMNS
允许使用多个列
来定义范围。范围是基于元组(多个列值的组合)的比较,而不是单个标量值。LIST COLUMNS
允许使用多个列
来定义值列表。 - 优势 :支持非整数类型的列(如
DATE
,DATETIME
,CHAR
,VARCHAR
)作为分区键,而无需使用函数(如YEAR()
)。支持多列分区键。 - 示例(RANGE COLUMNS):
sql
CREATE TABLE rcx (
a INT,
b INT,
c CHAR(3),
d INT
)
PARTITION BY RANGE COLUMNS(a, b, c) (
PARTITION p0 VALUES LESS THAN (5, 10, 'mmm'), -- 比较的是 (a, b, c) 这个元组
PARTITION p1 VALUES LESS THAN (10, 20, 'zzz'),
PARTITION p2 VALUES LESS THAN (MAXVALUE, MAXVALUE, MAXVALUE)
);
- 复合分区(子分区):
-
原理:先使用一种分区方式(如 RANGE),然后在每个分区内再使用另一种分区方式(如 HASH)。
-
常见场景:希望对数据先进行粗粒度划分(如按年),再在每个年份内进行细粒度的均匀分布。
-
示例:
sql
CREATE TABLE ts (
id INT,
purchased DATE
)
PARTITION BY RANGE (YEAR(purchased)) -- 第一级分区:按年
SUBPARTITION BY HASH (TO_DAYS(purchased)) -- 第二级分区:按天哈希
SUBPARTITIONS 2 ( -- 每个一级分区下面再分成 2 个子分区
PARTITION p0 VALUES LESS THAN (2021),
PARTITION p1 VALUES LESS THAN (2022),
PARTITION p2 VALUES LESS THAN MAXVALUE
);
三、 总结与选择建议
分区类型 | 关键字 | 适用场景 |
---|---|---|
RANGE | PARTITION BY RANGE |
按时间顺序的范围数据,易于归档和删除旧数据。 |
LIST | PARTITION BY LIST |
按离散的、分类的值进行分区,如地区、状态。 |
HASH | PARTITION BY HASH |
主要目的是将数据均匀分布,提高并发性能。 |
KEY | PARTITION BY KEY |
与 HASH 类似,但使用内置算法,常用于主键。 |
COLUMNS | PARTITION BY RANGE/LIST COLUMNS |
支持多列和非整数类型作为分区键,更灵活。 |
- 重要注意事项:
- 分区键必须是表主键或唯一索引的一部分。
- 分区并不是性能优化的"银弹",使用不当反而会降低性能。
- 在 MySQL 8.0 中,
InnoDB
是唯一支持原生分区的存储引擎。