MySQL: vincolo unico su colonna di grandi dimensioni


10

Sto cercando di creare una tabella InnoDB che contiene una VARCHARcolonna che può contenere fino a 3071 caratteri. Vorrei imporre un UNIQUEvincolo ai dati di questa colonna.

MySQL sembra imporre vincoli usando un indice. In InnoDB, le dimensioni dell'indice sembrano essere limitate a 767 byte, non abbastanza per la VARCHAR(3071)colonna che contiene i dati.

Qualche idea su come fare in modo che il database imponga l'unicità dei dati, senza compromettere la lunghezza massima dei dati o l'utilizzo di InnoDB?

Risposte:


10

Non vuoi un gen_clust_index gigantesco (indice cluster interno). Quella dimensione è immensamente enorme anche per un indice secondario.

Potrebbe essere necessario ricorrere a trigger o stored procedure per verificare la chiave con largo anticipo.

Si potrebbe anche pensare di eseguire una chiamata di funzione SHA1 utilizzando il VARCHAR(3071)campo. SHA1 restituirà un campo di 40 caratteri. Questo hash potrebbe essere proprio quello che devi indicizzare.

Supponi di avere questo

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

e vuoi fare un UNIQUEindice su txt. Prova l' approccio 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;

Quindi contali

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

Se i conteggi sono gli stessi, CONGRATULAZIONI !!! Ora hai un indice univoco di lunghezza 40. Puoi finire con:

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

Questo potrebbe essere più atomicamente, come sottolineato nei commenti qui sotto:

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

Esegui questo su qualunque tabella tu intenda avere questa grande colonna. Devi ricordare di aggiungere SHA1 dei dati insieme ai dati su INSERT.

La probabilità di chiavi duplicate è 1 su 2 alla 160a potenza (quella 1.4615016373309029182036848327163e + 48. Se ottengo la cifra esatta, la posterò un giorno).

Provaci !!!


+1 Questa è fondamentalmente un'ottima idea! Ho howerwer combinarlo con un trigger che verificherebbe se due digest sono uguali, anche il contenuto è lo stesso, esattamente come funziona una HashMap in Java ...
ppeterka,

1
Rolando - Ho molti cavilli: (1) sha1 dovrebbe essere ascii, non utf8. (2) sha1 potrebbe essere BINARY (20) se si utilizza HEX () e UNHEX (). (3) per rendere atomica la ridenominazione, senza tempi di inattività, RENAME TABLE mytable TO mytableold, mytablenew TO mytable. Quindi DROP TABLE mytableold dopo che sei soddisfatto. (4) Le quote indicate sono per una singola riga. (5) 2 64 è errato - è 2 160. (6) le probabilità per una tabella sono circa: "C'è una possibilità su 2 53 che una tabella con 2 53 righe abbia un dup sha1". (6a) È più probabile che tu ottenga da un asteroide mentre raccogli una mega-lotteria.
Rick James,

@RickJames hanno notato tutti i punti. Per favore, scusa la mia cattiva matematica per il punto 5, è 2 ^ 160. Ho modificato il n. 3 nella mia risposta.
RolandoMySQLDBA il

1
Ragazzi, le probabilità che presenti presumono: 1. SHA ha una distribuzione perfetta; e 2. l'input è perfettamente casuale. SHA non ha una distribuzione perfetta. Né nessun altro algoritmo di hashing. L'input non è perfettamente casuale e sebbene SHA, come altri digest, causino enormi cambiamenti nell'output per qualsiasi piccola modifica nell'input, è perfettamente possibile che alcuni set di input realizzerebbero lo stesso output e che quegli input abbiano qualche sistematico connessione tra loro. Ora, per lo più borbotta qui, poiché le probabilità sono molto basse; ma comunque, si dovrebbe essere diffidenti.
Shlomi Noach,

Le chiavi di hashing di @ShlomiNoach possono essere faticose. Di questo
passo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.