### 24.2.1范围划分

[](<>)[](<>)

按范围分区的表的分区方式是，每个分区都包含分区表达式值位于给定范围内的行。范围应该是连续的，但不能重叠，并且使用`价值低于`操作人员在接下来的几个示例中，假设您正在创建一个如下表，以保存由20家视频商店组成的连锁店（编号为1到20）的人员记录：

```
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 NOT NULL,
    store_id INT NOT NULL
);
```

笔记

这个`员工`这里使用的表没有主键或唯一键。虽然这些示例在本次讨论中如图所示工作，但您应该记住，在实践中，表极有可能具有主键、唯一键或两者，并且分区列的允许选择取决于用于这些键的列（如果存在）。有关这些问题的讨论，请参阅[第24.6.1节，“分区键、主键和唯一键”](partitioning-limitations-partitioning-keys-unique-keys.html).

根据您的需要，此表可以按范围以多种方式分区。一种方法是使用`店号`柱例如，您可能决定通过添加`按范围划分`条款如下所示：

```
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 NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_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)
);
```

在这个分区方案中，对应于在商店1到5工作的员工的所有行都存储在分区中`p0`，以分区方式存储在6号至10号门店的员工`p1`等等每个分区都是按从低到高的顺序定义的。这是公司的一项要求`按范围划分`句法；你可以认为它类似于一系列`如果否则。。。`在这方面，C或Java中的语句。

很容易确定包含数据的新行`（72，'米切尔'，'威尔逊'，'1998-06-25'，空，13）`被插入到分区中`p2`但是当你的连锁店增加了21<sup>圣</sup>百货商店在这项计划下，没有规则涵盖`店号`大于20，因此会出现错误，因为服务器不知道将其放置在何处。你可以使用“catchall”来防止这种情况发生`价值低于`条款[`创建表格`](create-table.html)语句，该语句提供大于显式指定的最高值的所有值：

```
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 NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_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
);
```

（与本章中的其他示例一样，我们假设默认的存储引擎是`InnoDB`.)

笔记

另一种避免在找不到匹配值时出错的方法是使用`忽视`关键字作为[`插入`](insert.html)陈述有关示例，请参见[第24.2.2节，“列表分区”](partitioning-list.html).另见[第13.2.6节“插入声明”](insert.html)，以获取有关`忽视`.

`最大值`表示始终大于最大可能整数值的整数值（在数学语言中，它用作最小上限）。现在，任何一行`店号`列值大于或等于16（定义的最高值）存储在分区中`p3`.在未来某个时候，当门店数量增加到25家、30家或更多时，你可以使用[`改变桌子`](alter-table-partition-operations.html)语句为存储区21-25、26-30等添加新分区（请参见[第24.3节，“分区管理”](partitioning-management.html)，了解如何执行此操作的详细信息）。

以大致相同的方式，您可以基于员工职务代码（即，基于工作范围）对表进行分区`工作代码`列值。例如，假设两位数的工作代码用于普通（店内）员工，三位数的代码用于办公室和支持人员，四位数的代码用于管理职位，您可以使用以下语句创建分区表：

```
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 NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (job_code) (
    PARTITION p0 VALUES LESS THAN (100),
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (10000)
);
```

在本例中，与店内工作人员相关的所有行都将存储在分区中`p0`，与办公室及支援人员有关的`p1`，以及与分区经理有关的`p2`.

也可以在中使用表达式`价值低于`条款。然而，MySQL必须能够计算表达式的返回值，作为`少于` (`<`)比较。

[](<>)

您可以使用基于两个表达式之一的表达式，而不是根据存储编号拆分表数据[`日期`](datetime.html)而不是列。例如，假设您希望根据每个员工离开公司的年份进行划分；也就是说[`年份（分开）`](date-and-time-functions.html#function_year).一个例子[`创建表格`](create-table.html)实现这种分区方案的语句如下所示：

```
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
);
```

在这个方案中，对于1991年之前离开的所有员工，行存储在分区中`p0`; 对于那些在1991年至1995年期间离开的人`p1`; 对于1996年至2000年期间离开的人`p2`; 对于2000年后离开的工人`p3`.

也可以按顺序对表进行分区`范围`，基于[`时间戳`](datetime.html)列，使用[`UNIX_时间戳（）`](date-and-time-functions.html#function_unix-timestamp)函数，如本例所示：

```
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)
);
```

任何其他涉及[`时间戳`](datetime.html)值是不允许的。（参见Bug#42849。）

当满足以下一个或多个条件时，范围分区特别有用：

-   您想要或需要删除“旧”数据。如果您使用的是前面所示的分区方案`员工`表，您可以简单地使用`改变表中的员工删除分区p0；`删除所有与1991年之前停止为公司工作的员工相关的行。（见[第13.1.9节“更改表格声明”](alter-table.html)和[第24.3节，“分区管理”](partitioning-management.html)，以获取更多信息。）对于包含大量行的表，这可能比运行[`删去`](delete.html)查询，例如`删除年份（分离）<=1990年的员工；`.

-   您希望使用一个包含日期或时间值的列，或者包含来自其他系列的值。

-   您经常运行直接依赖于用于分区表的列的查询。例如，在执行查询时，例如[`解释按门店id划分为“2000-01-01”和“2000-12-31”组的员工人数（*）；`](explain.html)，MySQL可以快速确定唯一的分区`p2`需要扫描，因为剩余的分区不能包含任何满足`哪里`条款看见[第24.4节，“分区修剪”](partitioning-pruning.html)，以获取有关如何实现这一点的更多信息。

    这种分区类型的一个变体是`范围列`分区。按分区`范围列`可以使用多列来定义分区范围，这些范围既适用于分区中行的放置，也适用于在执行分区修剪时确定特定分区的包含或排除。看见[第24.2.3.1节，“范围列分区”](partitioning-columns-range.html)，以获取更多信息。

[](<>)**基于时间间隔的分区方案。**如果您希望在MySQL 8.0中实现基于范围或时间间隔的分区方案，您有两个选项：

1.  将表按`范围`，对于分区表达式，使用一个在[`日期`](datetime.html), [`时间`](time.html)或[`约会时间`](datetime.html)列并返回一个整数值，如下所示：

    ```
    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
    );
    ```

    在MySQL 8.0中，还可以按`范围`基于[`时间戳`](datetime.html)列，使用[`UNIX_时间戳（）`](date-and-time-functions.html#function_unix-timestamp)函数，如本例所示：

    ```
    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)
    );
    ```

    在MySQL 8.0中，任何涉及[`时间戳`](datetime.html)值是不允许的。（参见Bug#42849。）

    笔记

    在MySQL 8.0中也可以使用[`UNIX_时间戳（时间戳_列）`](date-and-time-functions.html#function_unix-timestamp)作为按分区的表的分区表达式`列表`.然而，这样做通常并不实际。

2.  将表按`范围列`，使用[`日期`](datetime.html)或[`约会时间`](datetime.html)列作为分区列。例如`成员`可以使用`加入`直接列，如下所示：

    ```
    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 COLUMNS(joined) (
        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
    );
    ```

笔记

使用使用日期或时间类型而不是[`日期`](datetime.html)或[`约会时间`](datetime.html)不支持`范围列`.
