Spec-Zone .ru
спецификации, руководства, описания, API

17.5. Выбор раздела

MySQL 5.7 поддерживает явный выбор разделов и подразделов, которые, выполняя оператор, должны быть проверены на строки, соответствующие данный WHERE условие. Выбор раздела подобен сокращению раздела, в тот, единственные определенные разделы проверяются на соответствия, но отличается по двум ключевым отношениям:

  1. Разделы, которые будут проверены, определяются выпускающим оператора, в отличие от сокращения раздела, которое является автоматическим.

  2. Принимая во внимание, что сокращение раздела применяется только к запросам, явный выбор разделов поддерживается для обоих запросов и многих операторов DML.

SQL-операторы, поддерживающие явный выбор раздела, перечисляются здесь:

Остаток от этого раздела обсуждает явный выбор раздела, поскольку это применяется обычно к операторам, только перечисленным, и обеспечивает некоторые примеры.

Явный выбор раздела реализуется, используя a PARTITION опция. Для всех поддерживаемых операторов эта опция использует синтаксис, показанный здесь:

      PARTITION (partition_names)      partition_names:          partition_name, ...

Эта опция всегда следует за именем таблицы, которой принадлежат раздел или разделы. partition_names список разделенных запятой значений разделов или подразделов, которые будут использоваться. Каждое имя в этом списке должно быть именем существующего раздела или подраздела указанной таблицы; если какой-либо из разделов или подразделов не находится, сбои оператора с ошибкой (раздел'partition_name'не существует). Разделы и подразделы, названные в partition_names может быть перечислен в любом порядке, и может наложиться.

Когда PARTITION опция используется, только разделы и перечисленные подразделы проверяются на то, что они соответствовали строки. Эта опция может использоваться в a SELECT оператор, чтобы определить, какие строки принадлежат данному разделу. Считайте разделенную таблицу названной employees, создаваемое и заполненное использование операторов, показанных здесь:

SET @@SQL_MODE = '';CREATE TABLE employees  (    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,    fname VARCHAR(25) NOT NULL,    lname VARCHAR(25) NOT NULL,    store_id INT NOT NULL,    department_id INT NOT NULL)       PARTITION BY RANGE(id)  (        PARTITION p0 VALUES LESS THAN (5),        PARTITION p1 VALUES LESS THAN (10),        PARTITION p2 VALUES LESS THAN (15),        PARTITION p3 VALUES LESS THAN MAXVALUE);INSERT INTO employees VALUES    ('', 'Bob', 'Taylor', 3, 2), ('', 'Frank', 'Williams', 1, 2),     ('', 'Ellen', 'Johnson', 3, 4), ('', 'Jim', 'Smith', 2, 4),      ('', 'Mary', 'Jones', 1, 1), ('', 'Linda', 'Black', 2, 3),    ('', 'Ed', 'Jones', 2, 1), ('', 'June', 'Wilson', 3, 1),     ('', 'Andy', 'Smith', 1, 3), ('', 'Lou', 'Waters', 2, 4),      ('', 'Jill', 'Stone', 1, 4), ('', 'Roger', 'White', 3, 2),    ('', 'Howard', 'Andrews', 1, 2), ('', 'Fred', 'Goldberg', 3, 3),     ('', 'Barbara', 'Brown', 2, 3), ('', 'Alice', 'Rogers', 2, 2),      ('', 'Mark', 'Morgan', 3, 3), ('', 'Karen', 'Cole', 3, 2);

Можно видеть, какие строки сохранены в разделе p1 как это:

mysql> SELECT * FROM employees PARTITION (p1);+----+-------+--------+----------+---------------+| id | fname | lname  | store_id | department_id |+----+-------+--------+----------+---------------+|  5 | Mary  | Jones  |        1 |             1 ||  6 | Linda | Black  |        2 |             3 ||  7 | Ed    | Jones  |        2 |             1 ||  8 | June  | Wilson |        3 |             1 ||  9 | Andy  | Smith  |        1 |             3 |+----+-------+--------+----------+---------------+5 rows in set (0.00 sec)

Результатом является то же самое как получено запросом SELECT * FROM employees WHERE id BETWEEN 5 AND 9.

Чтобы получить строки из многократных разделов, предоставьте их имена как разграниченный запятой список. Например, SELECT * FROM employees PARTITION (p1, p2) возвраты все строки от разделов p1 и p2 в то время как, исключая строки от остающихся разделов.

Любой допустимый запрос против разделенной таблицы может быть переписан с a PARTITION опция, чтобы ограничить результат один или более требуемые разделы. Можно использовать WHERE условия, ORDER BY и LIMIT опции, и так далее. Можно также использовать агрегатные функции с HAVING и GROUP BY опции. Каждый из следующих запросов приводит к допустимому результату когда работающийся employees таблица как ранее определено:

mysql> SELECT * FROM employees PARTITION (p0,
        p2)    ->     WHERE lname LIKE 'S%';+----+-------+-------+----------+---------------+| id | fname | lname | store_id | department_id |+----+-------+-------+----------+---------------+|  4 | Jim   | Smith |        2 |             4 || 11 | Jill  | Stone |        1 |             4 |+----+-------+-------+----------+---------------+2 rows in set (0.00 sec)mysql> SELECT id, CONCAT(fname, ' ', lname) AS name     ->     FROM employees PARTITION (p0) ORDER BY lname;+----+----------------+| id | name           |+----+----------------+|  3 | Ellen Johnson  ||  4 | Jim Smith      ||  1 | Bob Taylor     ||  2 | Frank Williams |+----+----------------+4 rows in set (0.06 sec)mysql> SELECT store_id, COUNT(department_id) AS c     ->     FROM employees PARTITION (p1,p2,p3)     ->     GROUP BY store_id HAVING c > 4;+---+----------+| c | store_id |+---+----------+| 5 |        2 || 5 |        3 |+---+----------+2 rows in set (0.00 sec)

Операторы используя выбор раздела могут использоваться с таблицами, используя любой из типов разделения, поддерживаемых в MySQL 5.7. Когда таблица составляется, используя [LINEAR] HASH или [LINEAR] KEY разделение и имена разделов не определяются, MySQL автоматически называет разделы p0, p1, p2, ..., pN-1, где N число разделов. Для подразделов, не явно названных, MySQL присваивается автоматически к подразделам в каждом разделе pX имена pXsp0, pXsp1, pXsp2, ..., pXspM-1, где M число подразделов. Выполняясь против этой таблицы a SELECT (или другой SQL-оператор, для которого позволяется явный выбор раздела), можно использовать эти сгенерированные имена в a PARTITION опция, как показано здесь:

mysql> CREATE TABLE employees_sub (    ->     id INT NOT NULL AUTO_INCREMENT,    ->     fname VARCHAR(25) NOT NULL,    ->     lname VARCHAR(25) NOT NULL,    ->     store_id INT NOT NULL,    ->     department_id
        INT NOT NULL,    ->     PRIMARY KEY pk (id,
        lname)    -> )       ->     PARTITION BY RANGE(id)    ->     SUBPARTITION
        BY KEY (lname)    ->     SUBPARTITIONS 2 (    ->         PARTITION p0 VALUES LESS THAN (5),    ->         PARTITION p1 VALUES LESS THAN (10),    ->         PARTITION p2 VALUES LESS THAN (15),    ->         PARTITION p3 VALUES LESS THAN MAXVALUE    -> );Query OK, 0 rows affected (1.14 sec)mysql> INSERT INTO employees_sub   # re-use data in employees table    ->     SELECT * FROM employees;Query OK, 18 rows affected (0.09 sec)Records: 18  Duplicates: 0  Warnings: 0mysql> SELECT id, CONCAT(fname, ' ', lname) AS name    ->     FROM employees_sub PARTITION (p2sp1);+----+---------------+| id | name          |+----+---------------+| 10 | Lou Waters    || 14 | Fred Goldberg |+----+---------------+2 rows in set (0.00 sec)

Можно также использовать a PARTITION опция в SELECT часть INSERT ... SELECT оператор, как показано здесь:

mysql> CREATE TABLE employees_copy LIKE
        employees;Query OK, 0 rows affected (0.28 sec)mysql> INSERT
        INTO employees_copy     ->     SELECT * FROM employees
        PARTITION (p2);Query OK, 5 rows affected (0.04 sec)Records: 5  Duplicates: 0  Warnings: 0mysql> SELECT * FROM employees_copy;+----+--------+----------+----------+---------------+| id | fname  | lname    | store_id | department_id |+----+--------+----------+----------+---------------+| 10 | Lou    | Waters   |        2 |             4 || 11 | Jill   | Stone    |        1 |             4 || 12 | Roger  | White    |        3 |             2 || 13 | Howard | Andrews  |        1 |             2 || 14 | Fred   | Goldberg |        3 |             3 |+----+--------+----------+----------+---------------+5 rows in set (0.00 sec)

Выбор раздела может также использоваться с соединениями. Предположите, что мы создаем и заполняем две таблицы, используя операторы, показанные здесь:

CREATE TABLE stores (    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,    city VARCHAR(30) NOT NULL)    PARTITION BY HASH(id)    PARTITIONS 2;    INSERT INTO stores VALUES    ('', 'Nambucca'), ('', 'Uranga'),     ('', 'Bellingen'), ('', 'Grafton');    CREATE TABLE departments  (    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,    name VARCHAR(30) NOT NULL)    PARTITION BY KEY(id)    PARTITIONS 2;    INSERT INTO departments VALUES    ('', 'Sales'), ('', 'Customer Service'),     ('', 'Delivery'), ('', 'Accounting');

Можно явно выбрать разделы (или подразделы, или обоих) от любых из таблиц в соединении. (Отметьте что PARTITION опция, используемая, чтобы выбрать разделы из данной таблицы сразу, следует за именем таблицы, перед всеми другими опциями, включая любой табличный псевдоним.) Например, следующий запрос завоевывает репутацию, ID сотрудника, отдел, и город всех сотрудников, которые работают в продажах или отделе Поставки (раздел p1 из departments таблица) в хранилищах в любом из городов Nambucca и Bellingen (раздел p0 из stores таблица):

mysql> SELECT    ->     e.id AS 'Employee ID', CONCAT(e.fname, ' ', e.lname) AS Name,    ->     s.city AS City, d.name AS department    -> FROM employees AS e    ->     JOIN
        stores PARTITION (p1) AS s ON e.store_id=s.id    ->     JOIN
        departments PARTITION (p0) AS d ON e.department_id=d.id    -> ORDER BY e.lname;+-------------+---------------+-----------+------------+| Employee ID | Name          | City      | department |+-------------+---------------+-----------+------------+|          14 | Fred Goldberg | Bellingen | Delivery   ||           5 | Mary Jones    | Nambucca  | Sales      ||          17 | Mark Morgan   | Bellingen | Delivery   ||           9 | Andy Smith    | Nambucca  | Delivery   ||           8 | June Wilson   | Bellingen | Sales      |+-------------+---------------+-----------+------------+5 rows in set (0.00 sec)

Для получения общей информации об участвует в MySQL, см. Раздел 13.2.9.2,"JOIN Синтаксис".

Когда PARTITION опция используется с DELETE операторы, только те разделы (и подразделы, если кто-либо) перечисленный с опцией проверяются на строки, которые будут удалены. Любые другие разделы игнорируются, как показано здесь:

mysql> SELECT * FROM employees WHERE fname LIKE
        'j%';+----+-------+--------+----------+---------------+| id | fname | lname  | store_id | department_id |+----+-------+--------+----------+---------------+|  4 | Jim   | Smith  |        2 |             4 ||  8 | June  | Wilson |        3 |             1 || 11 | Jill  | Stone  |        1 |             4 |+----+-------+--------+----------+---------------+3 rows in set (0.00 sec)mysql> DELETE FROM employees PARTITION (p0, p1)     ->     WHERE fname LIKE 'j%';Query OK, 2 rows affected (0.09 sec)mysql> SELECT * FROM employees WHERE fname LIKE 'j%';+----+-------+-------+----------+---------------+| id | fname | lname | store_id | department_id |+----+-------+-------+----------+---------------+| 11 | Jill  | Stone |        1 |             4 |+----+-------+-------+----------+---------------+1 row in set (0.00 sec)

Только эти две строки в разделах p0 и p1 соответствие WHERE условие было удалено. Поскольку можно видеть от результата когда SELECT выполняется во второй раз, там остается строкой в таблице, соответствующей WHERE условие, но находящийся в различном разделе (p2).

UPDATE операторы используя явный выбор раздела ведут себя таким же образом; только строки в разделах, на которые ссылаются PARTITION опцию рассматривают, определяя строки, которые будут обновлены, как может быть замечен, выполняя следующие операторы:

mysql> UPDATE employees PARTITION
        (p0)     ->     SET store_id = 2 WHERE fname = 'Jill';Query OK, 0 rows affected (0.00 sec)Rows matched: 0  Changed: 0  Warnings: 0mysql> SELECT * FROM employees WHERE fname = 'Jill';+----+-------+-------+----------+---------------+| id | fname | lname | store_id | department_id |+----+-------+-------+----------+---------------+| 11 | Jill  | Stone |        1 |             4 |+----+-------+-------+----------+---------------+1 row in set (0.00 sec)mysql> UPDATE employees PARTITION (p2)    ->     SET store_id = 2 WHERE fname = 'Jill';Query OK, 1 row affected (0.09 sec)Rows matched: 1  Changed: 1  Warnings: 0mysql> SELECT * FROM employees WHERE fname = 'Jill';+----+-------+-------+----------+---------------+| id | fname | lname | store_id | department_id |+----+-------+-------+----------+---------------+| 11 | Jill  | Stone |        2 |             4 |+----+-------+-------+----------+---------------+1 row in set (0.00 sec)

Таким же образом, когда PARTITION используется с DELETE, только строки в разделе или разделах, названных в списке раздела, проверяются на удаление.

Для операторов, которые вставляют строки, поведение отличается по тому отказу найти, что подходящий раздел заставляет оператор перестать работать. Это - истина для обоих INSERT и REPLACE операторы, как показано здесь:

mysql> INSERT INTO employees PARTITION (p2) VALUES
        (20, 'Jan', 'Jones', 1, 3);ERROR 1729 (HY000): Found a row not matching the given partition setmysql> INSERT INTO employees PARTITION (p3) VALUES (20, 'Jan', 'Jones', 1,
        3);Query OK, 1 row affected (0.07 sec)mysql> REPLACE INTO employees PARTITION (p0) VALUES (20, 'Jan', 'Jones', 3, 2);ERROR 1729 (HY000): Found a row not matching the given partition setmysql> REPLACE INTO employees PARTITION (p3) VALUES (20, 'Jan', 'Jones', 3, 2);Query OK, 2 rows affected (0.09 sec)

Для операторов, которые пишут многократные строки в разделенную таблицу, которая использует InnoDB механизм хранения: Если любая строка в списке после VALUES не может быть записан одному из разделов, определенных в partition_names список, все сбои оператора и никакие строки пишутся. Для этого показывают INSERT операторы в следующем примере, снова используя employees таблица, составленная ранее:

mysql> ALTER TABLE employees    ->     REORGANIZE PARTITION p3 INTO (    ->         PARTITION p3 VALUES LESS THAN (20),    ->         PARTITION p4 VALUES LESS THAN (25),    ->         PARTITION p5 VALUES LESS THAN MAXVALUE    ->     );Query OK, 6 rows affected (2.09 sec)Records: 6  Duplicates: 0  Warnings: 0mysql> SHOW CREATE TABLE employees\G*************************** 1. row ***************************       Table: employeesCreate Table: CREATE TABLE `employees` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `fname` varchar(25) NOT NULL,  `lname` varchar(25) NOT NULL,  `store_id` int(11) NOT NULL,  `department_id` int(11) NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=latin1/*!50100 PARTITION BY RANGE (id)(PARTITION p0 VALUES LESS THAN (5) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (10) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (15) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (20) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (25) ENGINE = InnoDB, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */1 row in set (0.00 sec)mysql> INSERT INTO employees PARTITION (p3, p4)
        VALUES     ->     (24, 'Tim', 'Greene', 3, 1), (26, 'Linda',
        'Mills', 2,
        1);ERROR 1729 (HY000): Found a row not matching the given partition setmysql> INSERT INTO employees PARTITION (p3, p4. p5)
        VALUES     ->     (24, 'Tim', 'Greene', 3, 1), (26, 'Linda',
        'Mills', 2, 1);Query OK, 2 rows affected (0.06 sec)Records: 2  Duplicates: 0  Warnings: 0

Предыдущей является истина для обоих INSERT операторы и REPLACE операторы, которые пишут многократные строки.

В MySQL 5.7.1 и позже, выбор раздела отключается для таблиц, использующих механизм хранения, который предоставляет автоматическое разделение, такой как NDB. (Ошибка #14827952)