MySQL: уникальное ограничение на большой столбец

11

Я пытаюсь создать таблицу InnoDB, которая содержит VARCHARстолбец, который может содержать до 3071 символов. Я хотел бы ввести UNIQUEограничение на данные этого столбца.

Похоже, что MySQL применяет ограничения, используя индекс. В InnoDB размеры индекса ограничены 767 байтами - этого недостаточно для VARCHAR(3071)столбца, который содержит данные.

Любые мысли о том, как сделать так, чтобы база данных обеспечивала уникальность данных, без ущерба для максимальной длины данных или использования InnoDB?

Гус
источник

Ответы:

10

Вам не нужен гигантский gen_clust_index (внутренний кластерный индекс). Этот размер безбожно огромен даже для вторичного индекса.

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

Вы также можете подумать о выполнении вызова функции SHA1, используя VARCHAR(3071)поле. SHA1 вернет поле из 40 символов. Этот хеш может быть именно тем, что вам нужно индексировать.

Предположим, у вас есть это

CREATE TABLE mytable
(
    id int not null auto_increment,
    txt VARCHAR(3071),
    primary key (id)
) ENGINE=InnODB;

и вы хотите сделать UNIQUEиндекс на TXT. Попробуйте подход SHA1

CREATE TABLE mytablenew LIKE mytable;
ALTER TABLE mytable ADD txtsha1 CHAR(40);
ALTER TABLE mytable ADD UNIQUE KEY (txtsha1);
INSERT INTO mytablenew (id,txt,txtsha1)
SELECT id,txt,SHA1(txt) FROM mytable;

Затем посчитайте их

SELECT COUNT(1) FROM mytable;
SELECT COUNT(1) FROM mytablenew;

Если количество совпадений, ПОЗДРАВЛЯЕМ !!! Теперь у вас есть уникальный индекс длины 40. Вы можете закончить с:

ALTER TABLE mytable RENAME mytableold;
ALTER TABLE mytablenew RENAME mytable;
DROP TABLE mytableold;

Это может быть более атомарно, как указано в комментариях ниже:

RENAME TABLE mytable TO mytableold, mytablenew TO mytable;
DROP TABLE mytableold;

Выполните это на любой таблице, в которой вы собираетесь разместить этот большой столбец. Вы должны не забыть добавить SHA1 данных вместе с данными на INSERT.

Вероятность дублирования ключей составляет 1 к 2 к 160-й степени (это 1.4615016373309029182036848327163e + 48. Если я получу точную цифру, я опубликую ее когда-нибудь).

Попробуйте!

RolandoMySQLDBA
источник
+1 Это в принципе очень хорошая идея! Я хотел бы объединить его с триггером, который проверял бы, одинаковы ли два дайджеста, одинаково ли содержимое, точно так же, как работает HashMap в Java ...
ppeterka
1
Роландо - у меня много споров: (1) sha1 должно быть ascii, а не utf8. (2) sha1 может быть BINARY (20), если вы используете HEX () и UNHEX (). (3) чтобы сделать переименование атомарным, без простоя, сделайте RENAME TABLE mytable TO mytableold, mytablenew TO mytable. Затем DROP TABLE mytableold после того, как вы удовлетворены. (4) Котировки указаны для одной строки. (5) 2 64 неверно - это 2 160. (6) шансы для таблицы примерно такие: «В 2 53 есть один шанс, что у таблицы с 2 53 строками будет dup sha1». (6a) У вас больше шансов попасть на астероид, когда вы собираете деньги в мегамолете.
Рик Джеймс
@RickJames все точки отмечены. Пожалуйста, простите мою плохую математику за пункт № 5, это 2 ^ 160. Я поправил # 3 в своем ответе.
RolandoMySQLDBA
1
Ребята, шансы, которые вы представляете, предполагают: 1. SHA имеет идеальное распределение; и 2. вход совершенно случайный. SHA не имеет префектного распределения. Ни один другой алгоритм хеширования. Входные данные не являются совершенно случайными, и хотя SHA, как и другие дайджесты, приводит к огромным изменениям выходных данных при любых незначительных изменениях входных данных, вполне возможно, что некоторые наборы входных данных будут иметь одинаковый выходной сигнал, и что эти входные данные имеют некоторую систематическую связь между ними. Сейчас я в основном лепет здесь, так как шансы являются очень низкими; но все же следует быть осторожным.
Шломи Ноах
Ключи хэширования @ShlomiNoach могут быть рутиной. При такой скорости была бы приемлема даже функция ПАРОЛЬ ( palominodb.com/blog/2011/12/04/hashing-algorithm-mysql-password )
RolandoMySQLDBA