web-dev-qa-db-ja.com

MySQL:大きな列に対する一意の制約

最大3071文字を保持できるVARCHARカラムを含むInnoDBテーブルを作成しようとしています。この列のデータにUNIQUE制約を適用したいと思います。

MySQLはインデックスを使用して制約を強制しているようです。 InnoDBでは、インデックスサイズは767バイトに制限されているように見えます-データを保持しているVARCHAR(3071)カラムには十分ではありません。

最大データ長やInnoDBの使用法を犠牲にすることなく、データベースにデータの一意性を強制する方法についての考えはありますか?

10
Guus

巨大な gen_clust_index (内部クラスタ化インデックス)は必要ありません。セカンダリインデックスであっても、そのサイズは信じられないほど巨大です。

事前にキーをチェックするために、トリガーまたはストアドプロシージャを使用する必要がある場合があります。

VARCHAR(3071)フィールドを使用して SHA1 関数呼び出しを実行することも考えられます。 SHA1 は、40文字のフィールドを返します。このハッシュは、インデックスを作成するために必要なものです。

これがあるとしましょう

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

そして、txtにUNIQUEインデックスを作成したいとします。 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;

この大きな列を使用する予定の任意のテーブルでこれを実行します。 INSERTのデータとともに、データの SHA1 を追加することを忘れないでください。

重複キーのオッズは2分の1から160乗です(その1.4615016373309029182036848327163e + 48。正確な数値が得られれば、いつか投稿します)。

試してみる !!!

10
RolandoMySQLDBA