22.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, используемая здесь, не имеет первичных или уникальных ключей. Хотя примеры работают как показано для целей текущего обсуждения, следует иметь в виду, что на практике таблицы, скорее всего, будут иметь первичные ключи, уникальные ключи или оба, и допустимые варианты для столбцов разбиения зависят от столбцов, используемых для этих ключей, если таковые имеются. Для обсуждения этих вопросов см. Раздел 22.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
);
Другой способ избежать ошибки, когда не найдено совпадающее значение, — использовать ключевое слово IGNORE в качестве части оператора INSERT. Пример см. в разделе 22.2.2, «Разбиение по списку».
MAXVALUE представляет целое число, которое всегда больше наибольшего возможного целого числа (в математической терминологии оно служит верхним пределом). Теперь все строки, значение столбца store_id которых больше или равно 16 (наибольшее определённое значение), хранятся в разделе p3. В будущем — когда количество магазинов увеличится до 25, 30 или более — вы можете использовать оператор ALTER
TABLE для добавления новых разделов для магазинов 21-25, 26-30 и т. д. (подробнее см. раздел 22.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 года. (См. раздел 13.1.8, «Оператор ALTER TABLE» и раздел 22.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. См. раздел 22.4, «Оптимизация запросов для таблиц с разбиением» для получения дополнительной информации об этом.
Вариантом такого типа разбиения является разбиение по RANGE
COLUMNS. Разбиение по RANGE
COLUMNS позволяет использовать несколько столбцов для определения диапазонов разбиения, которые применяются как к размещению строк в разделах, так и для определения включения или исключения определенных разделов при выполнении оптимизации запросов для таблиц с разбиением. См. раздел 22.2.3.1, «Разбиение по столбцам диапазона» для получения дополнительной информации.
Схемы разбиения, основанные на временных интервалах. Если вы хотите реализовать схему разбиения, основанную на диапазонах или интервалах времени в MySQL 5.7, у вас есть два варианта:
-
Разбейте таблицу по
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 5.7 также можно разделить таблицу по
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 5.7 любые другие выражения, включающие значения
TIMESTAMP, запрещены. (См. ошибку #42849.)ПримечаниеВ MySQL 5.7 также можно использовать
UNIX_TIMESTAMP(timestamp_column)в качестве выражения разбиения для таблиц, разделяемых поLIST. Однако это обычно непрактично. -
Разбейте таблицу по
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.