22.2.2 Разбиение по списку
Разбиение по списку в MySQL во многом похоже на разбиение по диапазонам. Как и при разбиении по RANGE, каждый раздел должен быть явно определён. Основное различие между этими типами разбиения заключается в том, что при разбиении по списку каждый раздел определяется и выбирается на основе принадлежности значения столбца к одному из набора списков значений, а не к одному из набора смежных диапазонов значений. Это делается с помощью PARTITION BY
LIST(, где expr)expr — это значение столбца или выражение, основанное на значении столбца, возвращающее целое значение, а затем каждый раздел определяется с помощью VALUES IN
(, где value_list)value_list — это список целых чисел, разделённых запятыми.
В MySQL 5.7 можно сопоставлять только со списком целых чисел (и, возможно, NULL — см. Раздел 22.2.7, «Как MySQL обрабатывает NULL при разбиении») при разбиении по LIST.
Однако при использовании разбиения по LIST COLUMN в списках значений могут использоваться другие типы столбцов, что описано далее в этом разделе.
В отличие от разделов, определённых диапазоном, разделы по списку не обязательно должны быть объявлены в определённом порядке. Более подробную информацию о синтаксисе см. в Разделе 13.1.18, «Оператор 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
);
(Эта таблица используется в качестве основы для примеров в Разделе 22.2.1, «Разбиение по диапазонам».)
Предположим, что 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 5.7 все строки, относящиеся к сотрудникам, работающим в магазинах этого региона, могут быть удалены с помощью запроса 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 с разбиением по хэш или ключу для создания составного разбиения (подразбиения). См. Раздел 22.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 оператор считается единой транзакцией, поэтому наличие каких-либо несоответствующих значений приводит к полному отказу от оператора и ни одна строка не вставляется. Для таблицы, использующей не транзакционный механизм хранения, такой как MyISAM, любые строки, предшествующие строке с несоответствующим значением, вставляются, но любые строки, следующие за ней, не вставляются.
Вы можете заставить игнорировать этот тип ошибки, используя ключевое слово 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)
Из вывода следующего оператора можно увидеть, что строки с несоответствующими значениями столбца разбиения были молча отклонены, а строки без несоответствий были вставлены в таблицу:
mysql> TABLE h2;
+------+------+
| c1 | c2 |
+------+------+
| 7 | 5 |
| 1 | 9 |
| 2 | 5 |
+------+------+
3 rows in set (0.00 sec)
MySQL также поддерживает LIST COLUMNS разбиение, разновидность разбиения по LIST, которое позволяет использовать столбцы типов, отличных от целого, в качестве столбцов разбиения, а также использовать несколько столбцов в качестве ключей разбиения. Более подробную информацию см. в Разделе 22.2.3.2, «Разбиение по LIST COLUMNS».
© 2025 Oracle
Licensed under the GPLv2 License.