Necessity to use Index
SQLに疎いのでインデックスの有無によりどれくらいレスポンスが違うのか試してみた。
スキーマはこんな感じ。post_dataにはuser_id, post_dateでインデックスを張る。
create table post_data ( post_id int unsigned not null, #投稿ID user_id int unsigned not null, # ユーザID post_date int unsigned not null, # 投稿日時 content varchar(100) not null # 内容 ) type=InnoDB; alter table post_data add primary key (post_id), add index i1 (user_id, post_date), add index i2 (post_date); create table post_data2 ( post_id int unsigned not null, # 投稿ID user_id int unsigned not null, # ユーザID post_date int unsigned not null, # 投稿日時 content varchar(100) not null # 内容 ) type=InnoDB; alter table post_data2 add primary key (post_id);
データは20万行くらい突っ込むことにする。user_idは1〜10,000の中からランダムに決めるが、公平のためpost_dataとpost_data2には同じuser_idを入れる。
ベンチマークスクリプトは以下。
use Benchmark; timethese(500, { hasIndex => 'getList("post_data");', hasNoIndex => 'getList("post_data2");', }); sub getList { my $table = shift; my $user_id = int(rand 10000) + 10001; my $dbh = getHandle(); #まあ適当に my $sth = $dbh_d->prepare(<<"SQL"); select post, user_id, post_date,content from $table where user_id = ? order by post_date desc limit 10 SQL $sth->execute($user_id); while(my $rHash = $sth->fetchrow_hashref()) { #結果を取り出している風 } }
結果はベンチマークプログラム使うまでもなし。圧倒的にインデックスがないと遅い。
Benchmark: timing 500 iterations of hasIndex, hasNoIndex... hasIndex: 2 wallclock secs ( 0.12 usr + 0.17 sys = 0.29 CPU) @ 1724.14/s (n=500) (warning: too few iterations for a reliable count) hasNoIndex: 329 wallclock secs ( 0.20 usr + 0.33 sys = 0.53 CPU) @ 943.40/s (n=500)
150倍以上違う。こんなのを実サービスでやっちまったら逝ってよし、ですね。
ちなみにwallclock secsは子プロセスまで含めた実時間で、CPUのところはメインプロセスのみの模様(SQLのSelectは含んでいない)。
topしてみると、mysqlでCPUを99%喰ってるww
top - 16:38:51 up 1:17, 3 users, load average: 1.39, 0.93, 0.64 Tasks: 96 total, 1 running, 94 sleeping, 1 stopped, 0 zombie Cpu(s): 55.6% us, 44.4% sy, 0.0% ni, 0.0% id, 0.0% wa, 0.0% hi, 0.0% si Mem: 255736k total, 249092k used, 6644k free, 13364k buffers Swap: 524280k total, 0k used, 524280k free, 113224k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2705 mysql 16 0 118m 22m 4260 S 98.9 9.1 16:22.41 mysqld
結論
インデックスはきちんと張りましょう。