Ads by Google
新しい記事を書く事で広告が消せます。
みんなの動画サーチを実例としたPHPでの開発における負荷対策について 第6回 は前回に引き続いてデータベースの扱いについてです。
同じ1回の接続でも、SQL文自体がとても遅いものであると結局処理は遅くなってしまいます。そのため、発行するSQL文が適切であることも大事なポイントです。
まずは悪い例から。このmovieテーブルはトランザクション系のテーブルで、データ数は10万件を予定しています。
select * FROM `movie`;
こんなSQL文を発行していると、実際にレコード数が多くなった時にパンクしてしまいます。
こういうSQL文を発行するのが許されるのはレコード数が少ないマスタ系のテーブルだけです。必ずlimit構文などで制限をかけておきます。
これは極端な例ですが、sum()やcount()を使った集計結果など、開発時はデータが少なく見えるような場合は、トランザクション系テーブルのデータを全て取得するようなSQLもついうっかり使ってしまうことがあります。
また、こういううっかりミスをしたときにすぐ気がつくように、実運用に近いテストデータを使って開発すると良いです。テスト環境のテーブルには想定している最大のデータ数のレコードを持たせておきます。
その際、可能であればデータはテスト用の適当な値ではなく、実際に使われるものに近いものを使うのがベストです。たとえばハンドルネームを保存するものであるなら、「test1」などではなく、「中西明」のように本番と同じようなデータを入れておくべきです。
場合によっては特殊なデータも混ぜておきます。「中西☆明@'北海道'の"釧路"にイマス」のような感じですね。この例ほどひどくないとしても(技術者からすれば嫌がらせにしかみえませんね)、ユーザーは予想外の入力をするものです。
JOINを5つも6つも使った複雑なSQL文である、MYSQLで自己結合を行っている(MYSQLで自己結合を行うとレコード数によっては悲惨なほど時間がかかります)など、SQL文自体に速度の問題がある場合があります。これらはそのままでは使えないため、テーブル設計の見直しも含めた再作成が必要です。
こういった問題あるSQLも、実運用に近いテストデータを使っていると早期に気がつくことができます。
これはSQL文というよりもテーブル設計というべきですが、重要なのでとりあげます。
おなじSQLでもインデックスが張られているのといないのとでは大きな差が出ます。
このようなSQLで実際に計測してみたところ
SELECT * FROM `movie` WHERE `portal_type` LIKE 'YK';
インデックスありだと0.0009秒(EXPLAINを使って取得したrowsは11件)だった結果が、インデックスなしだと0.085秒 (同 11256件)と100倍近い差がでました。
インデックスを張ると更新系の処理が遅くなるのでただ張ればいいわけではありませんが、適切に利用されているインデックスは大きな改善をもたらします。
EXPLAINを使ってインデックスが適切に貼られているかチェックするのもいい工夫です。
重要なSQLについてはEXPLAINを使って
EXPLAIN SELECT * FROM `movie` WHERE `portal_type` LIKE 'YK';
rowsの値が過大なものになっていないかをチェックしておくと、インデックスの張り忘れにも気が付けます。
WHERE 構文で文字列が含まれるかを確かめる時に LIKE "%キーワード%"と行うことがよくあると思いますが、実は速度面を考えるとこのSQLはあまりよくありません。インデックスがまったくきかないため、ベタで検索することになってしまいます。どうしてもやむを得ない場合を除き、LIKE
"キーワード"のように%をつかわずにすむような設計にしておくことが望ましいです。
どうしても"%キーワード%"の形式を使わざるを得ないようなら、全文検索を行えるようにする必要があるかもしれません。
みんなの動画サーチでは上記を心がけたSQL文の発行を行っています。おかげさまで、今のところ問題あるSQLが原因の問題は発生していません。
みんなの動画サーチ 現在の人気動画