#### 24.2.3.1 RANGE COLUMNS 分区

范围列分区类似于范围分区，但允许您使用基于多个列值的范围来定义分区。此外，您可以使用整数类型以外的类型的列来定义范围。

`范围列`分区显着不同于`范围`通过以下方式进行分区：

-   `范围列`不接受表达式，只接受列名。

-   `范围列`接受一个或多个列的列表。

    `范围列`分区基于元组（列值列表）之间的比较，而不是标量值之间的比较。行的位置`范围列`分区也是基于元组之间的比较；这将在本节后面进一步讨论。

-   `范围列`分区列不限于整数列；细绳，[`日期`](datetime.html)和[`约会时间`](datetime.html)列也可以用作分区列。（看[第 24.2.3 节，“列分区”](partitioning-columns.html)，了解详情。）

    创建分区表的基本语法`范围列`显示在这里：


```
CREATE TABLE table_name
PARTITION BY RANGE COLUMNS(column_list) (
    PARTITION partition_name VALUES LESS THAN (value_list)[,
    PARTITION partition_name VALUES LESS THAN (value_list)][,
    ...]
)

column_list:
    column_name[, column_name][, ...]

value_list:
    value[, value][, ...]
```

笔记

不是全部[`创建表`](create-table.html)此处显示了创建分区表时可以使用的选项。有关完整信息，请参阅[第 13.1.20 节，“CREATE TABLE 语句”](create-table.html).

在刚刚显示的语法中，*`列列表`*是一个或多个列的列表（有时称为分区列列表），并且*`价值清单`*是一个值列表（即，它是一个分区定义值列表）。一种*`价值清单`*必须为每个分区定义提供，并且每个*`价值清单`*必须具有与*`列列表`*有列。一般来说，如果你使用*`ñ`*中的列`列`子句，然后每个`值小于`子句还必须提供一个列表*`ñ`*价值观。

分区列列表和定义每个分区的值列表中的元素必须以相同的顺序出现。此外，值列表中的每个元素必须与列列表中的相应元素具有相同的数据类型。但是，分区列列表和值列表中列名的顺序不必与主部分中表列定义的顺序相同[`创建表`](create-table.html)陈述。与分区表一样`范围`， 您可以使用`最大值`表示一个值，使得插入给定列的任何合法值始终小于该值。这是一个示例[`创建表`](create-table.html)有助于说明所有这些要点的声明：

```
mysql> CREATE TABLE rcx (
    ->     a INT,
    ->     b INT,
    ->     c CHAR(3),
    ->     d INT
    -> )
    -> PARTITION BY RANGE COLUMNS(a,d,c) (
    ->     PARTITION p0 VALUES LESS THAN (5,10,'ggg'),
    ->     PARTITION p1 VALUES LESS THAN (10,20,'mmm'),
    ->     PARTITION p2 VALUES LESS THAN (15,30,'sss'),
    ->     PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
    -> );
Query OK, 0 rows affected (0.15 sec)
```

桌子`rcx`包含列`一种`,`b`,`c`,`d`.提供给`列`子句按顺序使用这些列中的 3 个`一种`,`d`,`c`.用于定义分区的每个值列表包含 3 个相同顺序的值；也就是说，每个值列表元组的形式为 (`INT`,`INT`,`字符(3)`)，对应列使用的数据类型`一种`,`d`， 和`c`（以该顺序）。

将行放置到分区中是通过比较要插入的行中与`列`带有元组的子句`值小于`子句来定义表的分区。因为我们比较的是元组（即值的列表或集合）而不是标量值，所以`值小于`与`范围列`分区与简单的情况有所不同`范围`分区。在`范围`分区，一行生成一个表达式值，该表达式值等于一个限制值`值小于`永远不会放在相应的分区中；然而，当使用`范围列`分区，有时可能行的分区列列表的第一个元素的值等于 a 中第一个元素的值`值小于`值列表放置在相应的分区中。

考虑`范围`此语句创建的分区表：

```
CREATE TABLE r1 (
    a INT,
    b INT
)
PARTITION BY RANGE (a)  (
    PARTITION p0 VALUES LESS THAN (5),
    PARTITION p1 VALUES LESS THAN (MAXVALUE)
);
```

如果我们在这个表中插入 3 行，使得列值`一种`是`5`对于每一行，所有 3 行都存储在分区中`p1`因为`一种`列值在每种情况下都不少于 5，正如我们通过对[`INFORMATION_SCHEMA.PARTITIONS`](information-schema-partitions-table.html)桌子：

```
mysql> INSERT INTO r1 VALUES (5,10), (5,11), (5,12);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT PARTITION_NAME,TABLE_ROWS
    ->     FROM INFORMATION_SCHEMA.PARTITIONS
    ->     WHERE TABLE_NAME = 'r1';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0             |          0 |
| p1             |          3 |
+----------------+------------+
2 rows in set (0.00 sec)
```

现在考虑一个类似的表`rc1`使用`范围列`用两列分区`一种`和`b`中引用的`列`子句，创建如下所示：

```
CREATE TABLE rc1 (
    a INT,
    b INT
)
PARTITION BY RANGE COLUMNS(a, b) (
    PARTITION p0 VALUES LESS THAN (5, 12),
    PARTITION p3 VALUES LESS THAN (MAXVALUE, MAXVALUE)
);
```

如果我们将完全相同的行插入`rc1`正如我们刚刚插入`r1`，行的分布是完全不同的：

```
mysql> INSERT INTO rc1 VALUES (5,10), (5,11), (5,12);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT PARTITION_NAME,TABLE_ROWS
    ->     FROM INFORMATION_SCHEMA.PARTITIONS
    ->     WHERE TABLE_NAME = 'rc1';
+--------------+----------------+------------+
| TABLE_SCHEMA | PARTITION_NAME | TABLE_ROWS |
+--------------+----------------+------------+
| p            | p0             |          2 |
| p            | p1             |          1 |
+--------------+----------------+------------+
2 rows in set (0.00 sec)
```

这是因为我们比较的是行而不是标量值。我们可以将插入的行值与限制行值进行比较`值小于`用于定义分区的子句`p0`在表中`rc1`， 像这样：

```
mysql> SELECT (5,10) < (5,12), (5,11) < (5,12), (5,12) < (5,12);
+-----------------+-----------------+-----------------+
| (5,10) < (5,12) | (5,11) < (5,12) | (5,12) < (5,12) |
+-----------------+-----------------+-----------------+
|               1 |               1 |               0 |
+-----------------+-----------------+-----------------+
1 row in set (0.00 sec)
```

2个元组`(5,10)`和`(5,11)`评估为小于`(5,12)`，所以它们存储在分区中`p0`.由于 5 不小于 5 且 12 不小于 12，`(5,12)`被认为不小于`(5,12)`, 并存储在分区中`p1`.

这[`选择`](select.html)前面示例中的语句也可以使用显式行构造函数编写，如下所示：

```
SELECT ROW(5,10) < ROW(5,12), ROW(5,11) < ROW(5,12), ROW(5,12) < ROW(5,12);
```

有关在 MySQL 中使用行构造函数的更多信息，请参阅[第 13.2.11.5 节，“行子查询”](row-subqueries.html).

对于分区的表`范围列`仅使用单个分区列，分区中的行存储与分区的等效表相同`范围`.下列`创建表`语句创建一个分区表`范围列`使用 1 个分区列：

```
CREATE TABLE rx (
    a INT,
    b INT
)
PARTITION BY RANGE COLUMNS (a)  (
    PARTITION p0 VALUES LESS THAN (5),
    PARTITION p1 VALUES LESS THAN (MAXVALUE)
);
```

如果我们插入行`(5,10)`,`(5,11)`， 和`(5,12)`进入这个表格，我们可以看到它们的位置与表格相同`r`我们之前创建并填充：

```
mysql> INSERT INTO rx VALUES (5,10), (5,11), (5,12);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT PARTITION_NAME,TABLE_ROWS
    ->     FROM INFORMATION_SCHEMA.PARTITIONS
    ->     WHERE TABLE_NAME = 'rx';
+--------------+----------------+------------+
| TABLE_SCHEMA | PARTITION_NAME | TABLE_ROWS |
+--------------+----------------+------------+
| p            | p0             |          0 |
| p            | p1             |          3 |
+--------------+----------------+------------+
2 rows in set (0.00 sec)
```

也可以创建分区表`范围列`其中一个或多个列的限制值在连续的分区定义中重复。只要用于定义分区的列值元组严格递增，您就可以执行此操作。例如，以下每个[`创建表`](create-table.html)陈述有效：

```
CREATE TABLE rc2 (
    a INT,
    b INT
)
PARTITION BY RANGE COLUMNS(a,b) (
    PARTITION p0 VALUES LESS THAN (0,10),
    PARTITION p1 VALUES LESS THAN (10,20),
    PARTITION p2 VALUES LESS THAN (10,30),
    PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE)
 );

CREATE TABLE rc3 (
    a INT,
    b INT
)
PARTITION BY RANGE COLUMNS(a,b) (
    PARTITION p0 VALUES LESS THAN (0,10),
    PARTITION p1 VALUES LESS THAN (10,20),
    PARTITION p2 VALUES LESS THAN (10,30),
    PARTITION p3 VALUES LESS THAN (10,35),
    PARTITION p4 VALUES LESS THAN (20,40),
    PARTITION p5 VALUES LESS THAN (MAXVALUE,MAXVALUE)
 );
```

下面的语句也成功了，尽管乍一看它可能不会成功，因为 column 的限制值`b`是 25 用于分区`p0`和 20 用于分区`p1`，以及列的极限值`c`是 100 用于分区`p1`和 50 用于分区`p2`：

```
CREATE TABLE rc4 (
    a INT,
    b INT,
    c INT
)
PARTITION BY RANGE COLUMNS(a,b,c) (
    PARTITION p0 VALUES LESS THAN (0,25,50),
    PARTITION p1 VALUES LESS THAN (10,20,100),
    PARTITION p2 VALUES LESS THAN (10,30,50)
    PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
 );
```

在设计分区表时`范围列`，您始终可以通过使用[**mysql**](mysql.html)客户端，像这样：

```
mysql> SELECT (0,25,50) < (10,20,100), (10,20,100) < (10,30,50);
+-------------------------+--------------------------+
| (0,25,50) < (10,20,100) | (10,20,100) < (10,30,50) |
+-------------------------+--------------------------+
|                       1 |                        1 |
+-------------------------+--------------------------+
1 row in set (0.00 sec)
```

如果一个[`创建表`](create-table.html)语句包含未严格按递增顺序的分区定义，它会失败并出现错误，如下例所示：

```
mysql> CREATE TABLE rcf (
    ->     a INT,
    ->     b INT,
    ->     c INT
    -> )
    -> PARTITION BY RANGE COLUMNS(a,b,c) (
    ->     PARTITION p0 VALUES LESS THAN (0,25,50),
    ->     PARTITION p1 VALUES LESS THAN (20,20,100),
    ->     PARTITION p2 VALUES LESS THAN (10,30,50),
    ->     PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
    ->  );
ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition
```

当你得到这样的错误时，你可以通过在它们的列列表之间进行“小于”比较来推断哪些分区定义是无效的。在这种情况下，问题在于分区的定义`p2`因为用来定义它的元组不小于用来定义分区的元组`p3`，如此处所示：

```
mysql> SELECT (0,25,50) < (20,20,100), (20,20,100) < (10,30,50);
+-------------------------+--------------------------+
| (0,25,50) < (20,20,100) | (20,20,100) < (10,30,50) |
+-------------------------+--------------------------+
|                       1 |                        0 |
+-------------------------+--------------------------+
1 row in set (0.00 sec)
```

也可以为`最大值`出现在多个同一列中`值小于`使用时的子句`范围列`.但是，连续分区定义中各个列的限制值应该增加，不应该定义超过一个分区，其中`最大值`被用作所有列值的上限，并且这个分区定义应该出现在列表的最后`分区...值小于`条款。此外，您不能使用`最大值`作为多个分区定义中第一列的限制值。

如前所述，也可以使用`范围列`分区以使用非整数列作为分区列。（看[第 24.2.3 节，“列分区”](partitioning-columns.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
);
```

使用`范围列`分区，您可以创建此表的一个版本，根据员工的姓氏将每一行存储在四个分区之一中，如下所示：

```
CREATE TABLE employees_by_lname (
    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 COLUMNS (lname)  (
    PARTITION p0 VALUES LESS THAN ('g'),
    PARTITION p1 VALUES LESS THAN ('m'),
    PARTITION p2 VALUES LESS THAN ('t'),
    PARTITION p3 VALUES LESS THAN (MAXVALUE)
);
```

或者，您可能会导致`雇员`通过执行以下操作，使用此方案对先前创建的表进行分区[`更改表`](alter-table-partition-operations.html)陈述：

```
ALTER TABLE employees PARTITION BY RANGE COLUMNS (lname)  (
    PARTITION p0 VALUES LESS THAN ('g'),
    PARTITION p1 VALUES LESS THAN ('m'),
    PARTITION p2 VALUES LESS THAN ('t'),
    PARTITION p3 VALUES LESS THAN (MAXVALUE)
);
```

笔记

因为不同的字符集和排序规则有不同的排序顺序，所以使用的字符集和排序规则可能会影响表的哪个分区`范围列`当使用字符串列作为分区列时，将存储给定的行。此外，在创建此类表后更改给定数据库、表或列的字符集或排序规则可能会导致行分布方式发生变化。例如，当使用区分大小写的排序规则时，`'和'`排序之前`《安徒生》`，但是当使用不区分大小写的排序规则时，情况正好相反。

有关 MySQL 如何处理字符集和排序规则的信息，请参阅[第 10 章，*字符集、排序规则、Unicode*](charset.html).

同样，您可以导致`雇员`以这样一种方式对表进行分区，即每一行都存储在几个分区之一中，该分区基于相应员工被雇用的十年，使用[`更改表`](alter-table-partition-operations.html)此处显示的声明：

```
ALTER TABLE employees PARTITION BY RANGE COLUMNS (hired)  (
    PARTITION p0 VALUES LESS THAN ('1970-01-01'),
    PARTITION p1 VALUES LESS THAN ('1980-01-01'),
    PARTITION p2 VALUES LESS THAN ('1990-01-01'),
    PARTITION p3 VALUES LESS THAN ('2000-01-01'),
    PARTITION p4 VALUES LESS THAN ('2010-01-01'),
    PARTITION p5 VALUES LESS THAN (MAXVALUE)
);
```

看[第 13.1.20 节，“CREATE TABLE 语句”](create-table.html), 有关更多信息`按范围列分区`句法。
