Spec-Zone.ru › MySQL 8.4

26.2.1 Разбиение по диапазонам

Таблица, разбиение которой основано на диапазонах, разбивается таким образом, что каждый фрагмент содержит строки, для которых значение выражения разбиения находится в заданном диапазоне. Диапазоны должны быть непрерывными, но не перекрывающимися, и определяются с помощью оператора VALUES LESS THAN. В следующих примерах предположим, что вы создаёте таблицу для хранения записей персонала для цепочки из 20 видеомагазинов, пронумерованных от 1 до 20:

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
);
Примечание

Таблица employees, используемая здесь, не имеет первичных или уникальных ключей. Хотя примеры работают в соответствии с представленным описанием, вы должны помнить, что на практике таблицы, скорее всего, будут иметь первичные ключи, уникальные ключи или оба, и допустимые варианты столбцов разбиения зависят от столбцов, используемых для этих ключей, если таковые имеются. Подробнее об этих вопросах см. Раздел 26.6.1, «Ключи разбиения, первичные ключи и уникальные ключи».

Эту таблицу можно разбить по диапазонам несколькими способами, в зависимости от ваших потребностей. Один из способов — использовать столбец store_id. Например, вы можете решить разбить таблицу на 4 части, добавив предложение PARTITION BY RANGE, как показано здесь:

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
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN (21)
);

В этой схеме разбиения все строки, соответствующие сотрудникам, работающим в магазинах с номерами от 1 до 5, хранятся во фрагменте p0, строки, соответствующие сотрудникам, работающим в магазинах с номерами от 6 до 10, хранятся во фрагменте p1, и так далее. Каждый фрагмент определяется в порядке возрастания, от наименьшего к наибольшему. Это требование синтаксиса PARTITION BY RANGE; вы можете рассматривать это как аналогичный ряд операторов if ... elseif ... в C или Java в этом отношении.

Легко определить, что новая строка с данными (72, 'Mitchell', 'Wilson', '1998-06-25', DEFAULT, 7, 13) вставляется во фрагмент p2, но что произойдёт, если ваша сеть добавит 21-й магазин? В рамках этой схемы нет правила, которое охватывало бы строку, в которой store_id больше 20, поэтому возникает ошибка, поскольку сервер не знает, куда её поместить. Этого можно избежать, используя предложение “catchall” VALUES LESS THAN в операторе 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 NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

(Как и в других примерах в этой главе, мы предполагаем, что движок хранения по умолчанию — InnoDB.)

Другой способ избежать ошибки, когда не найдено соответствующего значения, — использовать ключевое слово IGNORE в операторе INSERT. Пример см. в Разделе 26.2.2, «Разбиение по спискам».

MAXVALUE представляет целочисленное значение, которое всегда больше наибольшего возможного целого значения (в математическом языке оно служит верхней границей). Теперь все строки, значение столбца store_id которых больше или равно 16 (наибольшее определённое значение), хранятся во фрагменте p3. В будущем — когда количество магазинов увеличится до 25, 30 или более — вы можете использовать оператор ALTER TABLE для добавления новых фрагментов для магазинов 21-25, 26-30 и так далее (подробнее см. Раздел 26.3, «Управление разбиением»).

Аналогичным образом, вы можете разбить таблицу по кодам должностей сотрудников — то есть по диапазонам значений столбца job_code. Например, предполагая, что двухзначные коды используются для обычных (внутримагазинных) сотрудников, трёхзначные — для сотрудников офиса и поддержки, а четырёхзначные — для руководящих должностей, вы можете создать разнесённую таблицу с помощью следующего оператора:

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
)
PARTITION BY RANGE (job_code) (
    PARTITION p0 VALUES LESS THAN (100),
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (10000)
);

В данном случае все строки, относящиеся к внутримагазинным сотрудникам, будут храниться во фрагменте p0, те, которые относятся к сотрудникам офиса и поддержки, — во фрагменте p1, и те, которые относятся к менеджерам, — во фрагменте p2.

Также возможно использовать выражение в предложениях VALUES LESS THAN. Однако MySQL должен быть способен вычислить возвращаемое значение выражения в рамках сравнения LESS THAN (<).

Вместо разделения данных таблицы по номеру магазина вы можете использовать выражение, основанное на одном из двух столбцов DATE. Например, предположим, что вы хотите разбить данные по году увольнения каждого сотрудника; то есть по значению YEAR(separated). Пример оператора 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 RANGE ( YEAR(separated) ) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1996),
    PARTITION p2 VALUES LESS THAN (2001),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

В этой схеме для всех сотрудников, уволенных до 1991 года, строки хранятся во фрагменте p0; для тех, кто уволился в период с 1991 по 1995 год, — во фрагменте p1; для тех, кто уволился в период с 1996 по 2000 год, — во фрагменте p2; и для любых работников, уволенных после 2000 года, — во фрагменте p3.

Также возможно разбить таблицу по RANGE, исходя из значения столбца TIMESTAMP, используя функцию UNIX_TIMESTAMP(), как показано в данном примере:

CREATE TABLE quarterly_report_status (
    report_id INT NOT NULL,
    report_status VARCHAR(20) NOT NULL,
    report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
    PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
    PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
    PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
    PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
    PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
    PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
    PARTITION p9 VALUES LESS THAN (MAXVALUE)
);

Любые другие выражения, включающие значения TIMESTAMP, запрещены. (См. ошибку #42849.)

Разбиение по диапазонам особенно полезно, когда выполняется одно или несколько из следующих условий:

  • Вы хотите или должны удалить «старые» данные. Если вы используете схему разбиения, показанную ранее для таблицы employees, вы можете просто использовать ALTER TABLE employees DROP PARTITION p0; для удаления всех строк, относящихся к сотрудникам, которые перестали работать в фирме до 1991 года. (См. Раздел 15.1.9, «Операция ALTER TABLE» и Раздел 26.3, «Управление разбиением» для получения дополнительной информации.) Для таблицы с большим количеством строк это может быть намного эффективнее, чем выполнение запроса DELETE, такого как DELETE FROM employees WHERE YEAR(separated) <= 1990;.

  • Вы хотите использовать столбец, содержащий значения дат или времени, или содержащий значения, полученные из какой-либо другой последовательности.

  • Вы часто выполняете запросы, которые напрямую зависят от столбца, используемого для разбиения таблицы. Например, при выполнении запроса, такого как EXPLAIN SELECT COUNT(*) FROM employees WHERE separated BETWEEN '2000-01-01' AND '2000-12-31' GROUP BY store_id;, MySQL может быстро определить, что нужно просмотреть только фрагмент p2, потому что оставшиеся фрагменты не могут содержать записей, удовлетворяющих предложению WHERE. Подробнее о том, как это делается, см. Раздел 26.4, «Обрезка фрагментов».

Вариант этого типа разбиения — разбиение по RANGE COLUMNS. Разбиение по RANGE COLUMNS позволяет использовать несколько столбцов для определения диапазонов разбиения, которые применяются как к размещению строк во фрагментах, так и для определения включения или исключения определённых фрагментов при выполнении обрезки фрагментов. Подробнее см. Раздел 26.2.3.1, «Разбиение по диапазонам столбцов».

Схемы разбиения, основанные на временных интервалах. Если вы хотите реализовать схему разбиения, основанную на диапазонах или интервалах времени в MySQL 8.4, у вас есть два варианта:

  1. Разбейте таблицу по RANGE, а в выражении разбиения используйте функцию, работающую со столбцом DATE, TIME или DATETIME и возвращающую целочисленное значение, как показано здесь:

    CREATE TABLE members (
        firstname VARCHAR(25) NOT NULL,
        lastname VARCHAR(25) NOT NULL,
        username VARCHAR(16) NOT NULL,
        email VARCHAR(35),
        joined DATE NOT NULL
    )
    PARTITION BY RANGE( YEAR(joined) ) (
        PARTITION p0 VALUES LESS THAN (1960),
        PARTITION p1 VALUES LESS THAN (1970),
        PARTITION p2 VALUES LESS THAN (1980),
        PARTITION p3 VALUES LESS THAN (1990),
        PARTITION p4 VALUES LESS THAN MAXVALUE
    );
    

    В MySQL 8.4 также возможно разбить таблицу по RANGE, исходя из значения столбца TIMESTAMP, используя функцию UNIX_TIMESTAMP(), как показано в данном примере:

    CREATE TABLE quarterly_report_status (
        report_id INT NOT NULL,
        report_status VARCHAR(20) NOT NULL,
        report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    )
    PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
        PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
        PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
        PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
        PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
        PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
        PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
        PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
        PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
        PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
        PARTITION p9 VALUES LESS THAN (MAXVALUE)
    );
    

    В MySQL 8.4 любые другие выражения, включающие значения TIMESTAMP, запрещены. (См. ошибку #42849.)

    Примечание

    В MySQL 8.4 также возможно использовать UNIX_TIMESTAMP(timestamp_column) в качестве выражения разбиения для таблиц, разнесённых по LIST. Однако это обычно непрактично.

  2. Разбейте таблицу по RANGE COLUMNS, используя столбец DATE или DATETIME в качестве столбца разбиения. Например, таблицу members можно определить с помощью столбца joined непосредственно, как показано здесь:

    CREATE TABLE members (
        firstname VARCHAR(25) NOT NULL,
        lastname VARCHAR(25) NOT NULL,
        username VARCHAR(16) NOT NULL,
        email VARCHAR(35),
        joined DATE NOT NULL
    )
    PARTITION BY RANGE COLUMNS(joined) (
        PARTITION p0 VALUES LESS THAN ('1960-01-01'),
        PARTITION p1 VALUES LESS THAN ('1970-01-01'),
        PARTITION p2 VALUES LESS THAN ('1980-01-01'),
        PARTITION p3 VALUES LESS THAN ('1990-01-01'),
        PARTITION p4 VALUES LESS THAN MAXVALUE
    );
    
Примечание

Использование разделяющих столбцов с типами данных даты или времени, отличными от DATE или DATETIME, не поддерживается в RANGE COLUMNS.

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-8.4-en/partitioning-range.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API