MySQL: Batasan unik pada kolom besar

10

Saya mencoba membuat tabel InnoDB yang berisi VARCHARkolom yang dapat menampung hingga 3071 karakter. Saya ingin menerapkan UNIQUEbatasan pada data kolom ini.

MySQL muncul untuk menegakkan batasan menggunakan indeks. Di InnoDB, ukuran indeks tampaknya dibatasi hingga 767 byte - tidak cukup untuk VARCHAR(3071)kolom yang menyimpan data.

Adakah pemikiran tentang bagaimana membuat basis data menegakkan keunikan data, tanpa mengurangi panjang data maksimum atau penggunaan InnoDB?

Guus
sumber

Jawaban:

10

Anda tidak ingin gen_clust_index raksasa (Indeks Clustered Internal). Ukuran itu sangat besar bahkan untuk indeks sekunder.

Anda mungkin harus menggunakan pemicu atau prosedur tersimpan untuk memeriksa kunci jauh-jauh hari.

Anda juga bisa berpikir tentang melakukan panggilan fungsi SHA1 menggunakan VARCHAR(3071)bidang. SHA1 akan mengembalikan bidang 40 karakter. Hash ini mungkin hanya apa yang perlu Anda indeks.

Misalkan Anda punya ini

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

dan Anda ingin membuat UNIQUEindeks pada txt. Coba pendekatan 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;

Lalu, hitung mereka

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

Jika Hitungannya Sama, SELAMAT !!! Sekarang Anda memiliki indeks panjang 40 yang unik. Anda dapat menyelesaikannya dengan:

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

Ini bisa lebih atomik seperti yang ditunjukkan dalam komentar di bawah ini:

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

Lakukan ini di meja apa pun yang Anda inginkan memiliki kolom besar ini. Anda harus ingat untuk menambahkan SHA1 data bersama dengan data setelahnya INSERT.

Peluang kunci duplikat adalah 1 dalam 2 ke kekuatan 160 (bahwa 1,4615016373309029182036848327163e + 48. Jika saya mendapatkan angka yang tepat, saya akan mempostingnya suatu hari nanti).

Cobalah !!!

RolandoMySQLDBA
sumber
+1 Ini pada dasarnya ide yang sangat bagus! Saya akan menggabungkannya dengan pemicu yang akan memeriksa apakah dua intisari sama, isinya juga sama, persis bagaimana HashMap di Jawa bekerja ...
ppeterka
1
Rolando - Saya punya banyak quibbles: (1) sha1 harus ascii, bukan utf8. (2) sha1 bisa menjadi BINARY (20) jika Anda menggunakan HEX () dan UNHEX (). (3) untuk membuat penggantian nama atom, tanpa downtime, lakukan RENAME TABLE mytable TO mytableold, mytablenew TO mytable. Kemudian DROP TABLE mytableold setelah Anda puas. (4) Peluang yang dikutip adalah untuk satu baris. (5) 2 64 salah - ini 160. (6) peluang untuk sebuah tabel adalah tentang: "Ada satu peluang dalam 2 53 bahwa sebuah tabel dengan 2 53 baris akan memiliki dup sha1." (6a) Anda cenderung mendapatkan asteroid saat mengoleksi lotere mega.
Rick James
@ RickJames semua poin dicatat. Maafkan matematika buruk saya untuk poin # 5, itu 2 ^ 160. Saya menyesuaikan # 3 dalam jawaban saya.
RolandoMySQLDBA
1
Kawan-kawan, peluang yang Anda hadirkan berasumsi: 1. SHA memiliki distribusi yang sempurna; dan 2. input benar-benar acak. SHA tidak memiliki distribusi prefek. Algoritma hashing juga tidak ada. Input tidak sepenuhnya acak, dan meskipun SHA, seperti halnya pencernaan lainnya, menyebabkan perubahan besar dalam output untuk setiap perubahan kecil pada input, sangat mungkin bahwa beberapa set input akan membuat untuk output yang sama, dan bahwa input tersebut memiliki beberapa sistematik. koneksi di antara mereka. Sekarang, aku kebanyakan mengoceh di sini, karena kemungkinan yang sangat rendah; tapi tetap saja, orang harus waspada.
Shlomi Noach
@ShlomiNoach hashing key bisa sangat menyusahkan. Pada tingkat ini, bahkan fungsi PASSWORD akan dapat diterima ( palominodb.com/blog/2011/12/04/hashing-algorithm-mysql-password )
RolandoMySQLDBA