MySQL: Einzigartige Einschränkung für große Spalten

10

Ich versuche, eine InnoDB-Tabelle zu erstellen, die eine VARCHARSpalte enthält , die bis zu 3071 Zeichen enthalten kann. Ich möchte eine UNIQUEEinschränkung für die Daten dieser Spalte erzwingen .

MySQL scheint Einschränkungen mithilfe eines Index durchzusetzen. In InnoDB scheinen die Indexgrößen auf 767 Byte begrenzt zu sein - nicht annähernd genug für die VARCHAR(3071)Spalte, in der sich die Daten befinden.

Irgendwelche Gedanken darüber, wie die Datenbank die Eindeutigkeit der Daten erzwingen kann, ohne Kompromisse bei der maximalen Datenlänge oder der Verwendung von InnoDB einzugehen?

Guus
quelle

Antworten:

10

Sie möchten keinen gigantischen gen_clust_index (Internal Clustered Index). Diese Größe ist selbst für einen Sekundärindex gottlos groß.

Möglicherweise müssen Sie frühzeitig auf Trigger oder gespeicherte Prozeduren zurückgreifen, um nach dem Schlüssel zu suchen.

Sie können auch überlegen, einen SHA1- Funktionsaufruf über das VARCHAR(3071)Feld auszuführen . SHA1 gibt ein 40-stelliges Feld zurück. Dieser Hash ist möglicherweise genau das, was Sie zum Indizieren benötigen.

Angenommen, Sie haben dies

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

und Sie möchten einen UNIQUEIndex für txt erstellen. Probieren Sie den SHA1- Ansatz aus

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;

Dann zähle sie

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

Wenn die Anzahl gleich ist, HERZLICHEN GLÜCKWUNSCH !!! Jetzt haben Sie einen eindeutigen Index mit einer Länge von 40. Sie können Folgendes beenden:

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

Dies könnte atomarer sein, wie in den Kommentaren unten ausgeführt:

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

Führen Sie dies für jede Tabelle aus, für die Sie diese große Spalte haben möchten. Sie müssen daran denken, den SHA1 der Daten zusammen mit den Daten auf hinzuzufügen INSERT.

Die Wahrscheinlichkeit von doppelten Schlüsseln beträgt 1 zu 2 nach der 160. Potenz (1.4615016373309029182036848327163e + 48. Wenn ich die genaue Zahl erhalte, werde ich sie eines Tages veröffentlichen).

Versuche es !!!

RolandoMySQLDBA
quelle
+1 Das ist im Grunde eine sehr gute Idee! Ich würde es jedoch mit einem Trigger kombinieren, der prüft, ob zwei Digests gleich sind, der Inhalt ist auch der gleiche, genau wie eine HashMap in Java funktioniert ...
ppeterka
1
Rolando - Ich habe viele Probleme: (1) sha1 sollte ascii sein, nicht utf8. (2) sha1 könnte BINARY (20) sein, wenn Sie HEX () und UNHEX () verwenden. (3) Um die Umbenennung ohne Ausfallzeit atomar zu machen, führen Sie RENAME TABLE mytable TO mytableold, mytablenew TO mytable durch. Dann DROP TABLE mytableold, nachdem Sie zufrieden sind. (4) Die angegebenen Quoten gelten für eine einzelne Reihe. (5) 2 64 ist falsch - es ist 2 160. (6) Die Wahrscheinlichkeit für einen Tisch ist ungefähr: "Es gibt eine Chance in 2 53, dass ein Tisch mit 2 53 Zeilen einen dup sha1 hat." (6a) Es ist wahrscheinlicher, dass Sie beim Sammeln in einer Mega-Lotterie an einem Asteroiden vorbeikommen.
Rick James
@ RickJames alle Punkte notiert. Bitte entschuldigen Sie meine schlechte Mathematik für Punkt 5, es ist 2 ^ 160. Ich habe # 3 in meiner Antwort angepasst.
RolandoMySQLDBA
1
Leute, die Chancen, die Sie präsentieren, gehen davon aus: 1. SHA hat eine perfekte Verteilung; und 2. die Eingabe ist vollkommen zufällig. SHA hat keine Präfektenverteilung. Auch kein anderer Hashing-Algorithmus. Die Eingabe ist nicht vollkommen zufällig, und obwohl SHA wie andere Digests bei jeder geringfügigen Änderung der Eingabe zu großen Änderungen der Ausgabe führt, ist es durchaus möglich, dass einige Sätze von Eingaben dieselbe Ausgabe ergeben und dass diese Eingaben systematisch sind Verbindung zwischen ihnen. Nun, ich plappern meistens hier, da die Chancen sind sehr gering; Trotzdem sollte man vorsichtig sein.
Shlomi Noach
@ShlomiNoach Hashing-Schlüssel können Plackerei sein. Bei dieser Rate wäre sogar die PASSWORD-Funktion akzeptabel ( palominodb.com/blog/2011/12/04/hashing-algorithm-mysql-password )
RolandoMySQLDBA