MySQL: contrainte unique sur une grande colonne

10

J'essaie de créer une table InnoDB qui contient une VARCHARcolonne pouvant contenir jusqu'à 3071 caractères. Je voudrais appliquer une UNIQUEcontrainte sur les données de cette colonne.

MySQL semble appliquer des contraintes à l'aide d'un index. Dans InnoDB, les tailles d'index semblent être limitées à 767 octets, ce qui n'est pas suffisant pour la VARCHAR(3071)colonne contenant les données.

Avez-vous des idées sur la façon de faire en sorte que la base de données applique l'unicité des données, sans compromettre la longueur maximale des données ou l'utilisation d'InnoDB?

Guus
la source

Réponses:

10

Vous ne voulez pas d'un gigantesque gen_clust_index (Index Clustered Interne). Cette taille est immensément énorme, même pour un indice secondaire.

Vous devrez peut-être recourir à des déclencheurs ou à des procédures stockées pour vérifier la clé bien à l'avance.

Vous pouvez également penser à effectuer un appel de fonction SHA1 à l'aide du VARCHAR(3071)champ. SHA1 renverra un champ de 40 caractères. Ce hachage peut être exactement ce dont vous avez besoin pour indexer.

Supposons que vous ayez ceci

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

et vous voulez faire un UNIQUEindex sur txt. Essayez l' approche 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;

Ensuite, comptez-les

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

Si les comptes sont les mêmes, FÉLICITATIONS !!! Vous avez maintenant un index unique de longueur 40. Vous pouvez terminer avec:

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

Cela pourrait être plus atomique, comme indiqué dans les commentaires ci-dessous:

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

Effectuez cette opération sur la table sur laquelle vous souhaitez disposer de cette grande colonne. Vous devez vous rappeler d'ajouter le SHA1 des données avec les données INSERT.

Les chances de dupliquer les clés sont de 1 sur 2 à la puissance 160e (soit 1,4615016373309029182036848327163e + 48. Si j'obtiens le chiffre exact, je le posterai un jour).

Essaie !!!

RolandoMySQLDBA
la source
+1 C'est fondamentalement une très bonne idée! Je le combinerais avec un déclencheur qui vérifierait si deux résumés sont identiques, le contenu est le même aussi, exactement comment fonctionne un HashMap en Java ...
ppeterka
1
Rolando - J'ai beaucoup de problèmes: (1) sha1 devrait être ascii, pas utf8. (2) sha1 pourrait être BINAIRE (20) si vous utilisez HEX () et UNHEX (). (3) pour rendre le changement de nom atomique, sans interruption, faites RENOMMER TABLE mytable TO mytableold, mytablenew TO mytable. Ensuite, DROP TABLE mytableold une fois que vous êtes satisfait. (4) Les cotes indiquées concernent une seule ligne. (5) 2 64 est faux - c'est 2 160. (6) la cote pour une table est d'environ: "Il y a une chance sur 2 53 qu'une table avec 2 53 lignes aura un dup sha1." (6a) Vous êtes plus susceptible de vous débrouiller avec un astéroïde en collectionnant dans une méga-loterie.
Rick James
@RickJames a noté tous les points. Veuillez excuser mes mauvaises mathématiques pour le point # 5, c'est 2 ^ 160. J'ai ajusté # 3 dans ma réponse.
RolandoMySQLDBA
1
Les gars, les chances que vous présentez supposent: 1. SHA a une distribution parfaite; et 2. l'entrée est parfaitement aléatoire. SHA n'a pas de distribution préfet. Aucun autre algorithme de hachage non plus. L'entrée n'est pas parfaitement aléatoire, et bien que SHA, comme d'autres digestions, cause d'énormes changements de sortie pour tout changement mineur d'entrée, il est parfaitement possible que certains ensembles d'entrées produisent la même sortie, et que ces entrées aient des connexion entre eux. Maintenant, je babille surtout ici, car les chances sont très faibles; mais encore faut-il se méfier.
Shlomi Noach
Les clés de hachage @ShlomiNoach peuvent être pénibles. À ce rythme, même la fonction PASSWORD serait acceptable ( palominodb.com/blog/2011/12/04/hashing-algorithm-mysql-password )
RolandoMySQLDBA