URLで検索する場合はハッシュ化してインデックスをつけるべし

URLで検索する場合はハッシュ化してインデックスをつけるべし

超恥ずかしい事実判明。
これまでブックマークサイトでURL等を重複チェックするときに

where url like 'http://'とかってしてて
重くなってきたので
varcharにインデックス張れんのかなーとか
全文検索エンジンがいるのかなーとか
思ってたが(>>varcharは255文字までインデックス張れる)、
一般的にurl等はハッシュ化してテーブルに格納して、そっち側をキーにするのが定石らしい。

インデックスの肥大化を防ぐ為に
1. インデックスが大きすぎる文字列型よりは整数型や日付/時刻型
2. 先頭Nバイトだけもつ
3. 数値変換したインデックスをもつ
ということが重要だそうです!


またmd5sha1ではなくCRC32というデータサイズの小さなハッシュを作り、
URLと一緒に検索させる方法が良いらしい。
by
http://d.hatena.ne.jp/a666666/20100928/1285607257
http://bohebohe.livedoor.biz/archives/51723503.html#


×

select
url
from
bookmark
where 
url = 'http:/aaaaaaaaaaaa'

select
url
from
bookmark
where 
url = 'http:/aaaaaaaaaaaa' and url_hash = CRC32('http://aaaaaaaaaaaa');

で、さっそく既存のテーブルに変更を加える↓

#カラムを追加
alter table clip_bookmark add site_url_hash int(10) default 0;
Query OK, 287290 rows affected (4 min 34.80 sec)
#インデックス追加
alter table clip_bookmark add index idx_site_url_hash(site_url_hash);
Query OK, 287296 rows affected (2 min 10.81 sec)
#インデックス確認
SHOW INDEX FROM clip_bookmark;

#(2011.02.17 intだとオーバーフローのためbigintへ変更)
ALTER TABLE clip_bookmark MODIFY site_url_hash bigint DEFAULT 0;



#URLからハッシュ値を生成するプロシージャー
delimiter //
drop procedure update_hash_url//
create procedure update_hash_url()
begin
    declare done int;
    declare cur cursor for
        select
            clip_bookmark_code,
            site_url,
            CRC32(site_url)
        from
            clip_bookmark
        where
            site_url_hash = 0
            limit 10000;
    declare exit handler for not found set done = 0;
    set done = 1;
    open cur;
    while done do
        fetch cur into
            local_clip_bookmark_code,
            local_site_url,
            local_site_url_hash
        ;
        update
            clip_bookmark
        set
            site_url_hash = local_site_url_hash
        where
            clip_bookmark_code = local_clip_bookmark_code
        ;
    end while;
    close cur;
end
//
delimiter ;
#プロシージャーを実行
call update_hash_url;

#あとはアプリケーション側の検索も諸々変更する
#完了