私は数百万のURLに対処する必要があるアプリケーションを作成しています。また、URLで検索する必要があります。ユニークなインデックス/制約なしにMySQLの重複行を防止しますか?
私のテーブルには、現在次のようになります。
CREATE TABLE Pages (
id bigint(20) unsigned NOT NULL,
url varchar(4096) COLLATE utf8_unicode_ci NOT NULL,
url_crc int(11) NOT NULL,
PRIMARY KEY (id),
KEY url_crc (url_crc)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Bツリー索引はがちURLの非常に非効率的になるので、このような構造の背後にある考え方は、URLのCRC32ハッシュでルックアップを行うことです(InnoDBはハッシュインデックスをサポートしていません)。 CRC32の重複した結果は、完全なURLとの比較によってフィルタリングされます。検索クエリの例は、次のようになります。
SELECT id
FROM Pages
WHERE url_crc = 2842100667
AND url = 'example.com/page.html';
重複したエントリが挿入されないようにするという問題があります。アプリケーションは、新しいエントリを挿入する前に既存のエントリをデータベースで常にチェックしますが、同じ新しいURLに対する複数のクエリが同時に行われ、CRC32とURLが重複して入力される可能性があります。
私は巨大なので、URLにユニークなインデックスを作成したくありません。また、すべてのインサートにテーブルをロックしておくと、同時のインサートのパフォーマンスが損なわれることになります。この問題を効率的に解決する方法はありますか?
編集:使用法についてもう少し詳しく説明すると、URLに応じてコンテンツを検索するためのリアルタイムテーブルです。 URLを参照することで、URLの内部IDを見つけて、そのIDを使用してページのコンテンツを見つけることができます。新しいURLは常にシステムに追加されています。私はそれらのURLがどれほど手に入るか分かりません。新しいURLが参照されると、同じURLを参照する同時リクエスト(おそらくは毎秒数百回)によって脅かされる可能性があります。そのため、新しいコンテンツを追加する際の競合状態が懸念されます。結果は直ちに必要で、遅れを読むことはできません(少し遅れても問題ありません)。
開始するには、新しいURLが1日に数千回しか追加されませんが、来年にはよりスケーラブルなソリューションに移行するまでに何度も処理する必要があります。
URLにユニークなインデックスを使用した場合の1つの問題は、URLの長さがユニークインデックスの最大長を超えることができることです。 CRC32トリックを落としても、重複したURLを防ぐという問題は解決しません。
URLのハッシュコピー(sha1?)を格納し、そのフィールドのインデックスを作成するとどうなりますか? DBの適切なトリガーを使用して、挿入/更新時にハッシュを更新/移入すると、メンテナンスのオーバーヘッドはごくわずかです。 –
CRC32はURLのハッシュです。これはSHA1よりはるかに小さいハッシュです(4バイト対20バイト)。私はアプリケーション側でそれを計算しています。 –
真実ですが、32ビットのみでは、衝突の確率が大幅に高まり、したがって偽陽性の偽薬が大幅に増加します。 –