現在のプロジェクトがかなりの規模のECサイトになるため、正確性とパフォーマンスのトレードオフなどが先日議題にあがりました。
完全なトレードオフではないのかもしれませんが、比較的あちらをたてればこちらが立たず。。となりやすいかとおもいます。
そこで得た知見を自分なりにまとめてみようかと・・・
パフォーマンス問題となりますとサーバーサイド絡みの場合、ほぼDBのアクセスをどのようにして押さえるかになると思います。
サーバサイドの場合、対策としては以下の2つのように大別されるかなあと思います。
- SQLのチューニングや見直し→そもそものロジックを見直し、発行回数自体を減らす、INDEXの活用を行う
- キャッシュの活用→staticキャッシュやインメモリDB
Contents
キャッシュのメリデメ
今回はキャッシュの使い所についての議論だったのですが、自分の場合、以下のケースでつかうことが多かったです。
- 画面読み込み時に毎回走るDB処理でスポット的に使う一時的な変数→staticキャッシュ
- これまた画面読み込み時に毎回走るマスタ系の処理→インメモリDB(memcachedやRedisなど)
キャッシュ(この場合インメモリのRedisなどを前提とするのですが)のメリデメとして
メリット
- DBへのアクセスを減らせ、DBの負荷がさがる
- アクセスが非常に高速
- 単純な構造のデータの保存と参照につよい
デメリット
- DBとの整合性を常に考える必要がある
- 整合性を取るために、処理の網羅性を考えるのが面倒
- 真の値(DB)の反映までに時間差がかかることがある
- 揮発性のあるデータなので長期間保存しておけない
- SQLのように複雑なデータの集計などができず、キーバリュー系の一時的なデータの保存にとどまる
のようなことが考えられると思います。
まとめると、超厳密には正しくないし、管理コストもあがるが、アクセス速度や負荷などが優先される場合(主に一時的なデータの参照)に使える手法、と言えるかと思います。
このような性質から単純なマスタの値だけでなく、参照系全般の処理に使えるかと思います。今の現場でも大量のアクセスがある一覧系の画面のAPIではDBではなくRedisを使っています。
参照系の処理の場合、
- ユーザーのアクセスが更新系に比べると頻繁であることが多い
- (あくまで)更新系よりは処理に厳密性を求められない
のような性質があるため、キャッシュが部分的に使えると思います。
既存の方針との比較など
高速化対策として、ちょっといままで行ってきた方針なども列挙しておこうかと思います。
個人的には一覧系で情報の参照が多い画面の場合
- ループ系のSQLをかく
- グルーピング系のSQLを書く
- サマリー系のテーブルを使う
といったことが多かったです。それぞれの特徴をみていきますと
ループ系のSQLをかく
一番単純で頭を使わない方法です。例えばユーザー一覧を取得する場合にループの中で1ユーザーごとにSQLを発行するような方法です。
メリット
- 単純で何も考えなくて良い
- 追加仕様があった際にも、ただ処理を追加するだけなので、簡単
デメリット
- パフォーマンス的に一番厳しく、時間もかかれば、DBへの負荷も大きくなる
グルーピング系のSQLを書く
パフォーマンスに一番寄与するのはSQLそのものの発行回数を少なくすることなので、グルーピングさせて1回のSQLで出力させることができれば、単純ですがかなり効果があります。
アクセス数が爆発的でないケースではこの方法で改善することが多いのではないかと思います。直でDBをみるので、正確性もSQLが正確ならば担保ができます。ビューを使うのも実質ここにいれます。
メリット
- 正確性をある程度保ちながら、パフォーマンスの向上が測れる
- 直でDBをみるので真の値とのタイムラグなどがない
デメリット
- SQLが肥大化しがちでメンテナンスが大変
- 複雑なSQLの場合、正確な値がとれているかの確認が面倒
- 表示項目などが多くなってくると必ずしもこの手法でとれない値もでてくる
サマリー系のテーブルを使う
グルーピング系だとSQLが肥大化したり、限界があることもあるので、サマリー系のテーブルを別途立てた方が良かったりします。
自分がやったのは勤怠報告みたいなテーブルだったんですが、日次で成績が記録されており、そこから月次のサマリーテーブルを作っていました。
メリット
- 高速かつDBへの負荷も下がる
- SQLが単純になる
- 記録としても参照しやすい
デメリット
- 真のデータ(サマリー元)とタイムラグが若干ある。
- 真のデータ(サマリー元)との乖離に気をつける必要が常にある。(元が更新された際にサマリーテーブルに値を入れるが、このトリガーがもれることが多い)
インメモリデータベースをつかうのはこの手法にちかいかなと思います。
サマリーかつインメモリなので超高速ですが、その代わり正確性を担保するための対策というのが大変になってきます。