22.2.4 Хэширование при разбиении
Разбиение с помощью HASH используется в основном для обеспечения равномерного распределения данных по заданному количеству разделов. При разбиении по диапазону или списку необходимо явно указать, в какой раздел будет помещено значение или набор значений заданного столбца; при разбиении с помощью хэширования MySQL позаботится об этом за вас, и вам нужно будет только указать значение или выражение, основанное на значении столбца, которое должно быть хэшировано, и количество разделов, на которые должна быть разделена таблицы.
Для разбиения таблицы с использованием разбиения с HASH необходимо добавить к оператору CREATE
TABLE предложение PARTITION BY HASH
(, где expr)expr — выражение, возвращающее целое число. Это может быть просто имя столбца, тип которого является одним из целочисленных типов MySQL. Кроме того, вы, скорее всего, захотите последовать этому предложением PARTITIONS
, где numnum — положительное целое число, представляющее количество разделов, на которые должна быть разделена таблица.
Для простоты, в примерах, которые следуют ниже, таблицы не используют ключи. Следует понимать, что, если таблица имеет уникальные ключи, каждый столбец, используемый в выражении разбиения для этой таблицы, должен быть частью каждого уникального ключа, включая первичный ключ. Дополнительную информацию см. в разделе 22.6.1 «Ключи разбиения, первичные ключи и уникальные ключи».
Следующее утверждение создаёт таблицу, которая использует хэширование по столбцу store_id и разделена на 4 раздела:
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 HASH(store_id)
PARTITIONS 4;
Если вы не включите предложение PARTITIONS, количество разделов по умолчанию равно 1.
Использование ключевого слова PARTITIONS без числа после него приводит к синтаксической ошибке.
Вы также можете использовать SQL-выражение, возвращающее целое число для expr. Например, вы можете разбить данные по году найма сотрудника. Это можно сделать, как показано ниже:
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 HASH( YEAR(hired) )
PARTITIONS 4;
expr должно возвращать непостоянное, неслучайное целое значение (то есть, оно должно изменяться, но быть детерминированным) и не должно содержать запрещённых конструкций, как описано в разделе 22.6 «Ограничения и пределы разбиения». Также следует помнить, что это выражение вычисляется каждый раз, когда строка вставляется или обновляется (или, возможно, удаляется); это означает, что очень сложные выражения могут привести к проблемам производительности, особенно при выполнении операций (таких как пакетные вставки), которые затрагивают большое количество строк одновременно.
Наиболее эффективная функция хэширования — это функция, которая работает с одним столбцом таблицы и значение которой увеличивается или уменьшается согласованно со значением столбца, так как это позволяет «прореживать» диапазоны разделов. То есть, чем ближе выражение изменяется со значением столбца, на основе которого оно основано, тем эффективнее MySQL может использовать выражение для разбиения по хэшу.
Например, если date_col — столбец типа DATE, то выражение TO_DAYS(date_col) изменяется прямо пропорционально значению date_col, так как при каждом изменении значения date_col значение выражения меняется согласованным образом. Изменение выражения YEAR(date_col) относительно date_col не так прямо, как TO_DAYS(date_col), поскольку не каждое возможное изменение в date_col производит эквивалентное изменение в YEAR(date_col). Тем не менее, YEAR(date_col) является хорошим кандидатом для функции хэширования, поскольку она изменяется прямо пропорционально части date_col, и нет никакого возможного изменения в date_col, которое производило бы непропорциональное изменение в YEAR(date_col).
В противоположность этому, предположим, что у вас есть столбец с именем int_col, тип которого INT. Теперь рассмотрим выражение POW(5-int_col,3) + 6. Это был бы плохой выбор для функции хэширования, потому что изменение значения int_col не гарантирует пропорциональное изменение значения выражения. Изменение значения int_col на заданную величину может привести к существенно различающимся изменениям значения выражения. Например, изменение int_col с 5 до 6 приводит к изменению -1 в значении выражения, но изменение значения int_col с 6 до 7 приводит к изменению -7 в значении выражения.
Иными словами, чем ближе график значения столбца по отношению к значению выражения следует прямой линии по уравнению y=, где cxc — какая-то ненулевая константа, тем лучше выражение подходит для хэширования. Это связано с тем, что чем нелинейнее выражение, тем неравномернее распределение данных по разделам, которое оно, как правило, производит.
Теоретически, прореживание также возможно для выражений, включающих более одного значения столбца, но определение подходящих таких выражений может быть довольно сложным и трудоёмким. По этой причине использование выражений хэширования, включающих несколько столбцов, не особо рекомендуется.
При использовании PARTITION BY HASH MySQL определяет, какой раздел num раздела использовать на основе модуля результата выражения. Другими словами, для заданного выражения expr раздел, в котором хранится запись, — это раздел номер N, где . Предположим, что таблица N =
MOD(expr,
num)t1 определена следующим образом, так что она имеет 4 раздела:
CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
PARTITION BY HASH( YEAR(col3) )
PARTITIONS 4;
Если вы вставляете запись в t1, значение col3 которой равно '2005-09-15', то раздел, в котором она хранится, определяется следующим образом:
MOD(YEAR('2005-09-01'),4)
= MOD(2005,4)
= 1
MySQL 5.7 также поддерживает вариант разбиения по хэшу, известный как линейное хэширование, который использует более сложный алгоритм для определения размещения новых строк, вставленных в разделяемую таблицу. Подробное описание этого алгоритма см. в разделе 22.2.4.1 «Разбиение с линейным хэшированием».
Предоставленное пользователем выражение вычисляется каждый раз, когда вставляется или обновляется запись. Оно также может (в зависимости от обстоятельств) вычисляться при удалении записей.
© 2025 Oracle
Licensed under the GPLv2 License.