MySQL Partitioning调研

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: MySQL Partitioning功能、相关限制的调研

MySQL Partitioning调研

用来记录MySQL Partitioning功能、相关限制的调研

RANGE Partition

语法见MySQL CREATE TABLE Syntax

partition_options:
    PARTITION BY
        { [LINEAR] HASH(expr)
        | [LINEAR] KEY [ALGORITHM={1|2}](column_list)
        | RANGE{(expr) | COLUMNS(column_list)}
        | LIST{(expr) | COLUMNS(column_list)} }
    [PARTITIONS num]
    [SUBPARTITION BY
        { [LINEAR] HASH(expr)
        | [LINEAR] KEY [ALGORITHM={1|2}](column_list) }
      [SUBPARTITIONS num]
    ]
    [(partition_definition [, partition_definition] ...)]

partition_definition:
    PARTITION partition_name
        [VALUES
            {LESS THAN {(expr | value_list) | MAXVALUE}
            |
            IN (value_list)}]

RANGE VALUES

每一个partition的value定义是从低到高。当插入的数值不在给出的值范围内的时候会报错,定义的value不在partition expression值范围内也会报错。

例如下面例子,由于-2不在partitoin expressioin c1的值域范围内而报错。

mysql>  CREATE TABLE tu (c1 BIGINT UNSIGNED)
PARTITION BY RANGE(c1) (
PARTITION p0 VALUES LESS THAN (-2),
PARTITION p1 VALUES LESS THAN (3),
PARTITION p2 VALUES LESS THAN (5),
PARTITION p3 VALUES LESS THAN (10 - 4),
PARTITION p4 VALUES LESS THAN (MAXVALUE)
);
ERROR 1563 (HY000): Partition constant is out of partition function domain

同时需要注意,RANGE分区定义使用的是less than,所以边界上的值属于下一个分区。

例如上面表格将p0中的value替换为2执行下面语句插入,

insert into tu values(3);
mysql> select * from tu partition(p1);
Empty set (0.00 sec)
mysql> select * from tu partition(p2);
+------+
| c1   |
+------+
|   3 |
+------+

建表语句values中的可计算表达式会存计算后的结果,下面例子中10-4就会计算出结果6存储。

mysql>  CREATE TABLE tu (c1 BIGINT UNSIGNED)
PARTITION BY RANGE(c1) (
PARTITION p0 VALUES LESS THAN (2),
PARTITION p1 VALUES LESS THAN (3),
PARTITION p2 VALUES LESS THAN (5),
PARTITION p3 VALUES LESS THAN (10 - 4),
PARTITION p4 VALUES LESS THAN (MAXVALUE)
);

mysql> show create table tu\G
*************************** 1. row ***************************
       Table: tu
Create Table: CREATE TABLE `tu` (
  `c1` bigint(20) unsigned DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (c1)
(PARTITION p0 VALUES LESS THAN (2) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (3) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (5) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (6) ENGINE = InnoDB,
 PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)

alte table add/drop partition

如果最初定义的value范围不够,可以通过ALTER TABLE来添加partition。

ALTER TABLE members ADD PARTITION (PARTITION p3 VALUES LESS THAN (2000));

如果需要删除某个partition,也可以指定drop。

ALTER TABLE tr DROP PARTITION p2;

其他建表示例

Note:对于TIMESTAMP列作为range partition的分区列,仅支持使用UNIX_TIMESTAMP函数。
原因见MySQL Bug #42849

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 RANGE ( YEAR(separated) ) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1996),
    PARTITION p2 VALUES LESS THAN (2001),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);


CREATE TABLE quarterly_report_status (
    report_id INT NOT NULL,
    report_status VARCHAR(20) NOT NULL,
    report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
    PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
    PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
    PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
    PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
    PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
    PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
    PARTITION p9 VALUES LESS THAN (MAXVALUE)
);

Note:查看MySQL执行所选择的分区可以使用EXPLAIN PARTITIONS

例如:

mysql> explain partitions select * from employees where year(separated) = 1990;
+----+-------------+-----------+-------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table     | partitions  | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-----------+-------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | employees | p0,p1,p2,p3 | ALL  | NULL          | NULL | NULL    | NULL |    4 | Using where |
+----+-------------+-----------+-------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> explain partitions select * from employees where separated = '1990-1-1';
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | employees | p0         | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

limitation

所有unique key(包括primary key)必须包含所有的partition columns

Partition Key的数据类型

除了partition by KEY, RANGE COLUMNS 或者 LIST COLUMNS,其他必须是integer的column或者表达式解析后是integer。同时partition key不能是subquery。

在MySQL中,subpartition只能是HASH/KEY partitioning。RANGE/LIST被subpartitioned

partition expression

1、存储过程、定义函数、插件程序和声明的变量不能出现在partition expression中。

2、很多函数不可以出现在partition expression中,MySQL允许在partition expression中使用的函数如下:

ABS() CEILING() (seeCEILING() and FLOOR()) DAY()
DAYOFMONTH() DAYOFWEEK() DAYOFYEAR()
DATEDIFF() EXTRACT() (seeEXTRACT() function with WEEK specifier) FLOOR() (seeCEILING() and FLOOR())
HOUR() MICROSECOND() MINUTE()
MOD() MONTH() QUARTER()
SECOND() TIME_TO_SEC() TO_DAYS()
TO_SECONDS() UNIX_TIMESTAMP()(with TIMESTAMPcolumns) WEEKDAY()
YEAR()   YEARWEEK()

3、算数运算符约束

+,-,*在partition expression中是被允许的,DIV运算也可以,但是'/'是不允许出现的。位操作符|, &, ^, <<, >>, 和 ~ 都不允许。

Note:这些限制不仅在partition expression中,在range分区的values表达式中也一样有如此限制。values中的表达式会存结果,而不是表达式。

mysql> create table tp(c1 int) partition by range(c1 - 10) (partition p0 values less than (('aA' = 'aa')), partition p1 values less than (5), partition p2 values less than MAXVALUE);
ERROR 1564 (HY000): This partition function is not allowed

mysql> create table tp(c1 int) partition by range(c1 - 10) (partition p0 values less than ((cast('123' as unsigned))), partition p1 values less than (5), partition p2 values less than MAXVALUE);
ERROR 1564 (HY000): This partition function is not allowed

mysql> create table tp(c1 int) partition by range(c1 - 10) (partition p0 values less than (10/2), partition p1 values less than (5), partition p2 values less than MAXVALUE);
ERROR 1564 (HY000): This partition function is not allowed

mysql> create table tp(c1 int) partition by range(c1 - 10) (partition p0 values less than (8 DIV 2), partition p1 values less than (5), partition p2 values less than MAXVALUE);
Query OK, 0 rows affected (0.09 sec)

SQL Mode

用户创建的分区表不会保留创建时候的SQL Mode。许多函数和操作的结果会受SQL Mode影响,因此创建分区表后改变SQL Mode可能会导致这些表的行为变化、冲突或者丢失数据。强烈建议建立分区表后不要改变SQL Mode。

同样SQL Mode在MySQL中也会影响partition table的副本,导致master和slave数据分布不一致,或者在master成功,在slave失败。

举例:

1、 错误处理。DIV函数受ERROR_FOR_DIVISION_BY_ZERO影响。

默认情况下,DIV 0,MOD 0 返回NULL。当设置ERROR_FOR_DIVISION_BY_ZERO后就会报错。

mysql>  SELECT @@sql_mode;
+-------------------+
| @@sql_mode        |
+-------------------+
| STRICT_ALL_TABLES |
+-------------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE tn (c1 INT) PARTITION BY LIST(1 DIV c1) (PARTITION p0 VALUES IN (NULL),PARTITION p1 VALUES IN (1));
mysql> INSERT INTO tn VALUES (NULL), (0), (1);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from tn partition(p0);
+------+
| c1   |
+------+
| NULL |
|    0 |
+------+
2 rows in set (0.00 sec)

设置SQL Mode 'ERROR_FOR_DIVISION_BY_ZERO'后,再次插入数据报错。
mysql> SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> INSERT INTO tn VALUES (NULL), (0), (1);
ERROR 1365 (22012): Division by 0

但原有数据读取和新建表不受影响
mysql> select * from tn where c1 = 0;
+------+
| c1   |
+------+
|    0 |
+------+
1 row in set, 1 warning (0.00 sec)

mysql> CREATE TABLE tn1 (c1 INT) PARTITION BY LIST(1 DIV c1) (PARTITION p0 VALUES IN (NULL),PARTITION p1 VALUES IN (1));
Query OK, 0 rows affected (0.07 sec)

2、表访问。UNSIGNED与SIGNED数值减法默认情况下产生UNSIGNED数值,如果是SIGNED数值就会报错。当设置 NO_UNSIGNED_SUBTRACTION后,结果就是SIGNED值。

mysql> select @@SQL_MODE;
+-------------------------+
| @@SQL_MODE              |
+-------------------------+
| NO_UNSIGNED_SUBTRACTION |
+-------------------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE tu (c1 BIGINT UNSIGNED) PARTITION BY RANGE(c1 - 10) ( PARTITION p0 VALUES LESS THAN (-5), PARTITION p1 VALUES LESS THAN (0),PARTITION p2 VALUES LESS THAN (5),PARTITION p3 VALUES LESS THAN (10 - 4),PARTITION p4 VALUES LESS THAN (MAXVALUE));

mysql> show create table tu\G
*************************** 1. row ***************************
       Table: tu
Create Table: CREATE TABLE `tu` (
  `c1` bigint(20) unsigned DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (c1 - 10)
(PARTITION p0 VALUES LESS THAN (-5) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (0) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (5) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (6) ENGINE = InnoDB,
 PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)


mysql> SET sql_mode='';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM tu;
ERROR 1563 (HY000): Partition constant is out of partition function domain
mysql> INSERT INTO tu VALUES (20);
ERROR 1563 (HY000): Partition constant is out of partition function domain

再创建对应表也会失败,因为-5不在c1 - 10的范围内。
mysql>  CREATE TABLE tu2 (c1 BIGINT UNSIGNED) PARTITION BY RANGE(c1 - 10) ( PARTITION p0 VALUES LESS THAN (-5), PARTITION p1 VALUES LESS THAN (3),PARTITION p2 VALUES LESS THAN (5),PARTITION p3 VALUES LESS THAN (10 - 4),PARTITION p4 VALUES LESS THAN (MAXVALUE));
ERROR 1563 (HY000): Partition constant is out of partition function domain

将-5改为2即成功。
mysql>  CREATE TABLE tu2 (c1 BIGINT UNSIGNED) PARTITION BY RANGE(c1 - 10) ( PARTITION p0 VALUES LESS THAN (2), PARTITION p1 VALUES LESS THAN (3),PARTITION p2 VALUES LESS THAN (5),PARTITION p3 VALUES LESS THAN (10 - 4),PARTITION p4 VALUES LESS THAN (MAXVALUE));
Query OK, 0 rows affected (0.13 sec)

但是插入数字如果小于10依然会报错。
mysql> insert into tu values(9);
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`test`.`tu`.`c1` - 10)'

最大partition数目

包含subpartition的最大partition数目除了NDB 存储引擎外为8192。

不支持query cache

分区表不支持Query cache。

Per-partition key caches.

MyISAM 支持。

InnoDB 存储Partition table不支持外键

ALTER TABLE ... ORDER BY.

仅排序各个partition内数据。

Replace/Insert 指定partition可能报指定数据不在选择的partition内

mysql>CREATE TABLE tr (c1 BIGINT UNSIGNED) PARTITION BY RANGE(c1) (
        PARTITION p0 VALUES LESS THAN (2),
        PARTITION P1 VALUES LESS THAN (10)
        );
mysql> insert into tr partition(p0) values(5);
ERROR 1748 (HY000): Found a row not matching the given partition set

FULLTEXT indexes.不支持

Partition Pruning

当有如下条件的时候肯定可以做Partition Pruning.

  • partition_column = constant
  • partition_column IN (constant1, constant2, ..., constantN)

经试验:
当partitoin_key为column的时候,可以根据给出的partition_column >、<、<=、>=来确定需要的partitions。
如果partition_key为+、-、*表达式则不会。

但是当表示式为 YEAR() 、TO_DAYS()或 TO_SECONDS()给出上述条件则可以确定需要的partitions。但是不具备year(partitoin_column) op const_value来确定partition的能力。

MySQL 实现基础文件

./partition_element.h
./sql_partition.cc
./partition_info.cc
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
监控 负载均衡 关系型数据库
MySQL技能完整学习列表13、MySQL高级特性——1、分区表(Partitioning)——2、复制(Replication)——3、集群(Clustering)
MySQL技能完整学习列表13、MySQL高级特性——1、分区表(Partitioning)——2、复制(Replication)——3、集群(Clustering)
53 0
|
消息中间件 SQL 算法
MySQL千万数据方案调研,一不小心直接打挂我系统
大家好,我是Leo。 之前聊的RocketMQ暂时放放,目前正在调研一个千万数据的处理方案。 在准备测试数据的时候,执行了个 select 把我电脑内存打光了。然后OOM,黑屏,宕机。。
MySQL千万数据方案调研,一不小心直接打挂我系统
|
存储 SQL 人工智能
MySQL监控-Datadog数据库监控调研
MySQL是最流行的数据库之一,在大多系统的后端的存储都有MySQL的身影,MySQL运行的是否健康,直接影响着整个系统的运行,数据库的瓶颈往往也是整个系统的瓶颈,其重要性不言而喻,所以对于MySQL的监控必不可少,及时发现MySQL运行中的异常,可以有效提高系统的可用性和用户体验。 本文主要介绍下MySQL如何做监控,以及对Datadog的Database Monitoring的一些简单调研。
1091 0
MySQL监控-Datadog数据库监控调研
|
SQL 存储 关系型数据库
|
SQL 关系型数据库 MySQL
|
监控 关系型数据库 MySQL
|
3天前
|
SQL 存储 关系型数据库
MySQL Cluster集群安装及使用
MySQL Cluster集群安装及使用
|
18天前
|
关系型数据库 MySQL 数据库
mysql卸载、下载、安装(window版本)
mysql卸载、下载、安装(window版本)
|
7天前
|
关系型数据库 MySQL 数据库
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
30 4
|
1天前
|
关系型数据库 MySQL 数据安全/隐私保护
安装mysql和远程连接
安装mysql和远程连接
8 0