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

17.2.7. Как MySQL Partitioning Handles NULL

Разделение в MySQL не делает ничего, чтобы отвергнуть NULL как значение выражения разделения, является ли это значением столбца или значением предоставленного пользователем выражения. Даже при том, что разрешается использовать NULL как значение выражения, которое должно иначе привести к целому числу, важно иметь в виду это NULL не число. Обработки реализации разделения MySQL NULL как являющийся меньше чем любой не -NULL значение, так же, как ORDER BY делает.

Это означает ту обработку NULL изменяется между разделением различных типов, и может произвести поведение, которое Вы не ожидаете, не готовитесь ли Вы к этому. Этот являющийся имеющим место, мы обсуждаем в этом разделе, как каждый MySQL, делящий тип, обрабатывает NULL значения, определяя раздел, в котором строка должна быть сохранена, и предоставить примеры каждому.

Обработка NULL с RANGE разделение. Если Вы вставляете строку в таблицу, разделенную RANGE так, что значение столбца, используемое, чтобы определить раздел, NULL, строка вставляется в самый низкий раздел. Считайте эти две таблицы в базе данных названными p, создаваемый следующим образом:

mysql> CREATE TABLE t1 (    ->     c1 INT,    ->     c2
        VARCHAR(20)    -> )    -> PARTITION BY RANGE(c1) (    ->     PARTITION p0 VALUES LESS THAN (0),    ->     PARTITION p1 VALUES LESS THAN (10),    ->     PARTITION p2 VALUES LESS THAN MAXVALUE    -> );Query OK, 0 rows affected (0.09 sec)mysql> CREATE TABLE t2 (    ->     c1
        INT,    ->     c2
        VARCHAR(20)    -> )    -> PARTITION BY RANGE(c1) (    ->     PARTITION p0 VALUES LESS THAN (-5),    ->     PARTITION p1 VALUES LESS THAN (0),    ->     PARTITION p2 VALUES LESS THAN (10),    ->     PARTITION p3 VALUES LESS THAN MAXVALUE    -> );Query OK, 0 rows affected (0.09 sec)

Можно видеть разделы, создаваемые этими двумя CREATE TABLE операторы используя следующий запрос против PARTITIONS таблица в INFORMATION_SCHEMA база данных:

mysql> SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS,
        AVG_ROW_LENGTH, DATA_LENGTH     >   FROM
        INFORMATION_SCHEMA.PARTITIONS     >   WHERE TABLE_SCHEMA =
        'p' AND TABLE_NAME LIKE 't_';+------------+----------------+------------+----------------+-------------+| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |+------------+----------------+------------+----------------+-------------+| t1         | p0             |          0 |              0 |           0 || t1         | p1             |          0 |              0 |           0 || t1         | p2             |          0 |              0 |           0 || t2         | p0             |          0 |              0 |           0 || t2         | p1             |          0 |              0 |           0 || t2         | p2             |          0 |              0 |           0 || t2         | p3             |          0 |              0 |           0 |+------------+----------------+------------+----------------+-------------+7 rows in set (0.00 sec)

(Для получения дополнительной информации об этой таблице, см. Раздел 19.14," INFORMATION_SCHEMA PARTITIONS Таблица".) Теперь позволяют нам заполнять каждую из этих таблиц с единственной строкой, содержащей a NULL в столбце, используемом в качестве ключа разделения, и, проверяют, что строки были вставлены, используя пару SELECT операторы:

mysql> INSERT INTO t1 VALUES (NULL, 'mothra');Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO t2 VALUES (NULL, 'mothra');Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM t1;+------+--------+| id   | name   |+------+--------+| NULL | mothra |+------+--------+1 row in set (0.00 sec)mysql> SELECT * FROM t2;+------+--------+| id   | name   |+------+--------+| NULL | mothra |+------+--------+1 row in set (0.00 sec)

Можно видеть, против которого разделы используются, чтобы сохранить вставленные строки, запуская повторно предыдущий запрос INFORMATION_SCHEMA.PARTITIONS и осмотр вывода:

mysql> SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS,
        AVG_ROW_LENGTH, DATA_LENGTH     >   FROM
        INFORMATION_SCHEMA.PARTITIONS     >   WHERE TABLE_SCHEMA =
        'p' AND TABLE_NAME LIKE 't_';+------------+----------------+------------+----------------+-------------+| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |+------------+----------------+------------+----------------+-------------+| t1 | p0 | 1 | 20 | 20 || t1         | p1             |          0 |              0 |           0 || t1         | p2             |          0 |              0 |           0 || t2 | p0 | 1 | 20 | 20 || t2         | p1             |          0 |              0 |           0 || t2         | p2             |          0 |              0 |           0 || t2         | p3             |          0 |              0 |           0 |+------------+----------------+------------+----------------+-------------+7 rows in set (0.01 sec)

Можно также демонстрировать, что эти строки были сохранены в самом низком разделе каждой таблицы, отбрасывая эти разделы, и затем запуская повторно SELECT операторы:

mysql> ALTER TABLE t1 DROP PARTITION
        p0;Query OK, 0 rows affected (0.16 sec)mysql> ALTER TABLE t2
        DROP PARTITION p0;Query OK, 0 rows affected (0.16 sec)mysql> SELECT
        * FROM t1;Empty set (0.00 sec)mysql> SELECT * FROM t2;Empty set (0.00 sec)

(Для получения дополнительной информации по ALTER TABLE ... DROP PARTITION, см. Раздел 13.1.6,"ALTER TABLE Синтаксис".)

NULL также обрабатывается таким образом для того, чтобы разделить выражения тот SQL использования функции. Предположите, что мы определяем таблицу, используя a CREATE TABLE оператор, такой как этот:

CREATE TABLE tndate (    id INT,    dt DATE)PARTITION BY RANGE( YEAR(dt) ) (    PARTITION p0 VALUES LESS THAN (1990),    PARTITION p1 VALUES LESS THAN (2000),    PARTITION p2 VALUES LESS THAN MAXVALUE);

Как с другими функциями MySQL, YEAR(NULL) возвраты NULL. Строка с a dt значение столбца NULL обрабатывается, как если бы выражение разделения, оцененное к значению меньше чем любое другое значение, и так, вставляется в раздел p0.

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

mysql> CREATE TABLE ts1 (    ->     c1 INT,    ->     c2
        VARCHAR(20)    -> )    -> PARTITION BY LIST(c1) (    ->     PARTITION p0 VALUES IN (0, 3, 6),    ->     PARTITION p1 VALUES IN (1, 4, 7),    ->     PARTITION p2 VALUES IN (2, 5, 8)    -> );Query OK, 0 rows affected (0.01 sec)mysql> INSERT INTO ts1 VALUES (9, 'mothra');ERROR 1504 (HY000): Table has no partition for value 9mysql> INSERT INTO ts1 VALUES (NULL, 'mothra');ERROR 1504 (HY000): Table has no partition for value NULL

Только строки, имеющие a c1 значение между 0 и 8 включительно может быть вставлен в ts1. NULL падения вне этого диапазона, точно так же как число 9. Мы можем составить таблицы ts2 и ts3 наличие значения перечисляет содержащий NULL, как показано здесь:

mysql> CREATE TABLE ts2 (    ->     c1 INT,    ->     c2 VARCHAR(20)    -> )    -> PARTITION BY LIST(c1) (    ->     PARTITION p0 VALUES IN (0, 3, 6),    ->     PARTITION p1 VALUES IN (1, 4, 7),    ->     PARTITION p2 VALUES IN (2, 5, 8),    ->     PARTITION p3 VALUES IN (NULL)    -> );Query OK, 0 rows affected (0.01 sec)mysql> CREATE TABLE ts3 (    ->     c1 INT,    ->     c2 VARCHAR(20)    -> )    -> PARTITION BY LIST(c1) (    ->     PARTITION p0 VALUES IN (0, 3, 6),    ->     PARTITION p1 VALUES IN (1, 4, 7, NULL),    ->     PARTITION p2 VALUES IN (2, 5, 8)    -> );Query OK, 0 rows affected (0.01 sec)

Когда определение значения перечисляет для того, чтобы разделить, Вы можете (и если) обработка NULL так же, как Вы были бы любое другое значение. Например, оба VALUES IN (NULL) и VALUES IN (1, 4, 7, NULL) допустимы, как VALUES IN (1, NULL, 4, 7), VALUES IN (NULL, 1, 4, 7), и так далее. Можно вставить наличие строки NULL для столбца c1 в каждую из таблиц ts2 и ts3:

mysql> INSERT INTO ts2 VALUES (NULL,
        'mothra');Query OK, 1 row affected (0.00 sec)mysql> INSERT
        INTO ts3 VALUES (NULL, 'mothra');Query OK, 1 row affected (0.00 sec)

Выпуская соответствующий запрос против INFORMATION_SCHEMA.PARTITIONS, можно определить, какие разделы использовались, чтобы сохранить строки, только вставленные (мы принимаем, как в предыдущих примерах, что разделенные таблицы создавались в p база данных):

mysql> SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS,
        AVG_ROW_LENGTH, DATA_LENGTH     >   FROM
        INFORMATION_SCHEMA.PARTITIONS     >   WHERE TABLE_SCHEMA =
        'p' AND TABLE_NAME LIKE 'ts_';+------------+----------------+------------+----------------+-------------+| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |+------------+----------------+------------+----------------+-------------+| ts2        | p0             |          0 |              0 |           0 || ts2        | p1             |          0 |              0 |           0 || ts2        | p2             |          0 |              0 |           0 || ts2 | p3 | 1 | 20 | 20 || ts3        | p0             |          0 |              0 |           0 || ts3 | p1 | 1 | 20 | 20 || ts3        | p2             |          0 |              0 |           0 |+------------+----------------+------------+----------------+-------------+7 rows in set (0.01 sec)

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

Обработка NULL с HASH и KEY разделение. NULL обрабатывается несколько по-другому для таблиц, разделенных HASH или KEY. В этих случаях, любое выражение раздела, которое приводит к a NULL значение обрабатывается, как если бы его возвращаемое значение было нулем. Мы можем проверить это поведение, исследуя эффекты на файловую систему составления таблицы, разделенной HASH и заполнение этого с записью, содержащей соответствующие значения. Предположите, что у Вас есть таблица th (также в p база данных) создаваемое использование следующего оператора:

mysql> CREATE TABLE th (    ->     c1 INT,    ->     c2
        VARCHAR(20)    -> )    -> PARTITION BY HASH(c1)    -> PARTITIONS
        2;Query OK, 0 rows affected (0.00 sec)

Разделы, принадлежащие этой таблице, могут быть просмотрены, используя запрос, показанный здесь:

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

Отметьте это TABLE_ROWS поскольку каждый раздел 0. Теперь вставьте две строки в th чей c1 значения столбцов NULL и 0, и проверяют, что эти строки были вставлены, как показано здесь:

mysql> INSERT INTO th VALUES (NULL, 'mothra'), (0,
        'gigan');Query OK, 1 row affected (0.00 sec)mysql> SELECT *
        FROM th;+------+---------+| c1   | c2      |+------+---------+| NULL | mothra  |+------+---------+|    0 | gigan   |+------+---------+2 rows in set (0.01 sec)

Вспомните это для любого целого числа N, значение NULL MOD Nвсегда NULL. Для таблиц, которые делятся HASH или KEY, этот результат лечат от того, что он определил корректный раздел как 0. Проверка INFORMATION_SCHEMA.PARTITIONS таблица еще раз, мы можем видеть, что обе строки были вставлены в раздел p0:

mysql> SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS,
        AVG_ROW_LENGTH, DATA_LENGTH     >   FROM
        INFORMATION_SCHEMA.PARTITIONS     >   WHERE TABLE_SCHEMA =
        'p' AND TABLE_NAME ='th';+------------+----------------+------------+----------------+-------------+| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |+------------+----------------+------------+----------------+-------------+| th | p0 | 2 | 20 | 20 || th         | p1             |          0 |              0 |           0 |+------------+----------------+------------+----------------+-------------+2 rows in set (0.00 sec)

Если Вы повторяете это использование в качестве примера PARTITION BY KEY вместо PARTITION BY HASH в определении таблицы можно проверить легко это NULL также обрабатывается как 0 для этого типа разделения.