26.2.2 Разбиение по списку
Разбиение по списку в MySQL во многом похоже на разбиение по диапазонам. Как и при разбиении по RANGE, каждый раздел должен быть явно определен. Основное различие между этими двумя типами разбиения состоит в том, что при разбиении по списку каждый раздел определяется и выбирается на основе принадлежности значения столбца к одному из набора списков значений, а не к одному из набора непрерывных диапазонов значений. Это делается с помощью PARTITION BY
LIST(, где expr)expr — это значение столбца или выражение, основанное на значении столбца, возвращающее целое число, а затем каждый раздел определяется с помощью VALUES IN
(, где value_list)value_list — это список целых чисел, разделенных запятыми.
В MySQL 8.4 возможно сопоставление только со списком целых чисел (и, возможно, NULL — см. Раздел 26.2.7, «Как MySQL обрабатывает NULL при разбиении»), при разбиении по LIST.
Однако при использовании разбиения по списку могут использоваться другие типы столбцов в списках значений, что описано далее в этом разделе.
В отличие от разделов, определенных диапазоном, разделы по списку не обязательно должны быть объявлены в определенном порядке. Более подробную синтаксическую информацию см. в Разделе 15.1.20, «Оператор CREATE TABLE».
В следующих примерах предполагается, что основное определение разделяемой таблицы предоставляется оператором CREATE TABLE, показанным здесь:
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
);
(Эта таблица используется в качестве основы для примеров в Разделе 26.2.1, «Разбиение по диапазонам». Как и в других примерах разбиения, предполагается, что default_storage_engine равно InnoDB.)
Предположим, что 20 видеомагазинов распределены по 4 франчайзинговым сетям, как показано в следующей таблице.
| Регион | Идентификаторы магазинов |
|---|---|
| Север | 3, 5, 6, 9, 17 |
| Восток | 1, 2, 10, 11, 19, 20 |
| Запад | 4, 12, 13, 14, 18 |
| Центр | 7, 8, 15, 16 |
Для разбиения этой таблицы таким образом, чтобы строки магазинов, относящихся к одному региону, хранились в одном разделе, можно использовать оператор CREATE TABLE, показанный здесь:
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 LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);
Это упрощает добавление или удаление записей сотрудников, относящихся к конкретным регионам, в таблицу. Например, предположим, что все магазины в регионе Запад проданы другой компании. В MySQL 8.4 все строки, относящиеся к сотрудникам, работающим в магазинах этого региона, могут быть удалены с помощью запроса ALTER TABLE employees TRUNCATE PARTITION
pWest, который может выполняться гораздо эффективнее, чем эквивалентный оператор DELETE оператор DELETE FROM employees WHERE store_id IN
(4,12,13,14,18);. (Использование ALTER TABLE
employees DROP PARTITION pWest также удалит все эти строки, но также удалит раздел pWest из определения таблицы; для восстановления первоначальной схемы разбиения таблицы потребуется использовать оператор ALTER TABLE ... ADD
PARTITION.)
Как и при разбиении по RANGE, можно объединить разбиение по LIST с разбиением по хэшу или ключу для создания составного разбиения (подразбиения). См. Раздел 26.2.6, «Подразбиение».
В отличие от разбиения по RANGE, нет “ловушки”, такой как MAXVALUE; все ожидаемые значения для выражения разбиения должны быть покрыты в клаузах PARTITION
... VALUES IN (...). Оператор INSERT, содержащий несоответствующее значение столбца разбиения, завершается ошибкой, как показано в этом примере:
mysql> CREATE TABLE h2 (
-> c1 INT,
-> c2 INT
-> )
-> PARTITION BY LIST(c1) (
-> PARTITION p0 VALUES IN (1, 4, 7),
-> PARTITION p1 VALUES IN (2, 5, 8)
-> );
Query OK, 0 rows affected (0.11 sec)
mysql> INSERT INTO h2 VALUES (3, 5);
ERROR 1525 (HY000): Table has no partition for value 3
При вставке нескольких строк с помощью одного оператора INSERT в одну таблицу InnoDB, InnoDB рассматривает оператор как единую транзакцию, поэтому наличие любых несоответствующих значений приводит к полному отказу оператора и вставке строк не происходит.
Вы можете заставить проигнорировать этот тип ошибки, используя ключевое слово IGNORE, хотя для каждой строки с несоответствующими значениями столбца разбиения выводится предупреждение, как показано здесь.
mysql> TRUNCATE h2;
Query OK, 1 row affected (0.00 sec)
mysql> TABLE h2;
Empty set (0.00 sec)
mysql> INSERT IGNORE INTO h2 VALUES (2, 5), (6, 10), (7, 5), (3, 1), (1, 9);
Query OK, 3 rows affected, 2 warnings (0.01 sec)
Records: 5 Duplicates: 2 Warnings: 2
mysql> SHOW WARNINGS;
+---------+------+------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------+
| Warning | 1526 | Table has no partition for value 6 |
| Warning | 1526 | Table has no partition for value 3 |
+---------+------+------------------------------------+
2 rows in set (0.00 sec)
Вы можете увидеть в выводе следующего оператора TABLE, что строки с несоответствующими значениями столбца разбиения были молча отклонены, а строки без несоответствующих значений были вставлены в таблицу:
mysql> TABLE h2;
+------+------+
| c1 | c2 |
+------+------+
| 7 | 5 |
| 1 | 9 |
| 2 | 5 |
+------+------+
3 rows in set (0.00 sec)
MySQL также поддерживает разбиение по LIST COLUMNS, разновидность разбиения по LIST, позволяющую использовать столбцы типов, отличных от целого числа, в качестве столбцов разбиения и использовать несколько столбцов в качестве ключей разбиения. Дополнительную информацию см. в Разделе 26.2.3.2, «Разбиение по столбцам списка».
© 2025 Oracle
Licensed under the GPLv2 License.