与えられたテーブル:
CREATE TABLE mytable (
field_a CHAR(15) NOT NULL DEFAULT '',
field_b MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
field_c SMALLINT UNSIGNED NOT NULL DEFAULT 0,
field_d SMALLINT UNSIGNED NOT NULL DEFAULT 0,
field_e CHAR(1) NULL DEFAULT '',
field_f SMALLINT UNSIGNED NOT NULL DEFAULT 0
) ENGINE=MyISAM DEFAULT CHARACTER SET=UTF8 COLLATE utf8_general_ci;
必要なインデックス:
ALTER TABLE mytable ADD UNIQUE INDEX idx_key (field_a, field_b);
データサイズは約51 Mioです。行。次の問題:
試行1:データがテーブルにある後でインデックスを作成しようとすると、重複キーエラーで失敗します。失敗したキーを選択すると、1行のみ(!)の行が返されます。
[23000][1062] Duplicate entry 'aaaaaaaaaaaaaaa-11111' for key 'idx_key'
SELECT COUNT(*) FROM mytable WHERE field_a='aaaaaaaaaaaaaaa' AND field_b='11111'
1(!)を返します
試行2:空のテーブルにインデックスを作成するか、結合された秘密キーを作成してからデータをテーブルに入れると、テーブルには51 Mioのうち27のみが含まれます。行(!).
一意のインデックスに何らかの制限やバグはありますか?
MariaDB 10.0.20を使用しています。助けてください。
更新1
一意の行の数
SELECT COUNT(DISTINCT field_a,field_b) from mytable;
50 Mio行を返します。したがって、約1つのMioの重複があります。ただし、これは27 Mioが試行2から、または誤った例外が試行1から説明できません。
更新2
試行2で使用されたテーブル:
CREATE TABLE mytable (
field_a CHAR(15) NOT NULL DEFAULT '',
field_b MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
field_c SMALLINT UNSIGNED NOT NULL DEFAULT 0,
field_d SMALLINT UNSIGNED NOT NULL DEFAULT 0,
field_e CHAR(1) NULL DEFAULT '',
field_f SMALLINT UNSIGNED NOT NULL DEFAULT 0,
UNIQUE KEY idx_key (field_a, field_b)
) ENGINE=MyISAM DEFAULT CHARACTER SET=UTF8 COLLATE utf8_general_ci;
更新3
試行2エラーが解決されました
テーブルにデータを追加するには、それぞれに複数の値行を持つINSERTステートメントを使用します。挿入の単一の値が一意制約に違反した場合、他のすべての値も挿入されず、50 Mioではなく27 Mio行が発生しました。
アプローチ1:ただし、データベースが削除されて再作成された後でも、重複したエントリメッセージが間違っているというバグがまだ残っていますが、これは私が生きることができる/しなければならない悪です。
Valueaaaaaaaaaaaaaaa-11111
メッセージ内
[23000][1062] Duplicate entry 'aaaaaaaaaaaaaaa-11111' for key 'mykey'
実際に違反を引き起こす値です。 MariaDBとMySQLのバグのようです。
プランA:バッチ挿入で_INSERT IGNORE
_を使用します。そうすれば、dupキーは問題を引き起こしません。
プランB:INDEX
ではなくUNIQUE
を使用してテーブルに挿入します。次に、重複をどうするかを決める前に、重複を調査できます。
CHAR(15) utf8
が45バイトを占めることを理解している 常にほとんどの_ROW_FORMATs
_?おそらくVARCHAR(15)
のほうがいいでしょうか? (FIXED
がMyISAMでより優れていることについての暴力的な妻の話を引用しないでください。)
または、おそらくデータは古いIPv4文字列でしょうか?これらは_CHARACTER SET ascii
_で正常に機能します。CHAR(15)
の場合は15バイト、VARCHAR(15)
の場合は1〜16バイトです。では、IPv6はどうでしょうか?そして、範囲を比較できないことについては?