商品数を増やしたときのパフォーマンスをあげる

商品数がとても多いサイトだと、EC-CUBEでは著しくパフォーマンスが低下してしまいます。
「商品数が何件ぐらいなら大丈夫?」
「大幅な改造をせずに、商品数の多いサイトを構築できないの?」
そんな疑問に答えるべく実験をしてみました。
実験したEC-CUBE環境は、以下の通りです。

  • VER:EC-CUBE ver2.4.0
  • DB:PostgreSQL ver8.1.11
  • CPU:Pentium DC 2.2GHz
  • メモリ:4GB

商品データ自動生成スクリプトを使って以下の条件で商品を追加

  • 商品カテゴリ1つに対して商品1000件
  • カテゴリ・規格は1商品につき、1種類。
  • 1000件単位で商品を追加

以下のA・Bのケースでフロントの商品一覧画面(html/products/list.php)の表示が完了するまでの時間を計測しました。
A検索条件なしで一覧を表示する
Bカテゴリを指定して一覧を表示する
(1)ノーマル状態のEC-CUBEの限界は1000商品!?
まず、EC-CUBEをインストールしただけの状態だと、どのくらいまで商品を増やせるのか実験してみました。
結果は以下の通りです。
A条件なしの一覧
商品数15000件までだと遅くても2秒以内で表示されました。
しかし、商品数16000件になると突然遅くなり、200秒以上かかってしまいました。
Bカテゴリ指定の一覧
商品数1000件で1.7秒
商品数2000件で9.0秒
商品数3000件で20.8秒
商品数4000件で34.4秒
商品数5000件で55.3秒かかりました。
表示時間は商品数に応じて加速度的に増加してしまっています。
しかし、たった2000件でページを表示するのに9秒もかかってしまっては、とても買い物する気にはなれません。

そこで、ノーマルのEC-CUBEでは1000商品くらいまで、と考えたほうがよさそう、と思ってしまいました。
(後述ですが、DBのパラメタチューニングでもうちょいいけそうです)

(2)並び替え機能を犠牲にすれば速くなる!?
商品数16000件で遅くなった件を調査していて、ソートの処理が重いという原因に行き当たりました。EC-CUBEでは一覧に表示されている商品のソート順が指定されていない場合、dtb_product_categoriesのrank、dtb_categoryのrankを使ってソートしています。そのためのテーブルのJOINに時間がかかっているようです。そこで、デフォルトの表示順の機能を見捨てて、新着順か価格順で表示するようにするとどうだろうか、という点を調査しました。
まず、ソート順のデフォルトが新着順や価格順になるように改造してみました。下の例では、ソート順が新着順になるようにしています。「date」の部分をpriceにすると価格順になります。

data/class/pages/products/LC_Page_Products_List.php
    function process() {
    
          (省略)

          //表示順序の保存
-         $this->orderby = isset($_POST['orderby']) ? $_POST['orderby'] : "";
+         $this->orderby = isset($_POST['orderby']) ? $_POST['orderby'] : "date";

          (省略)
          
-         if (!isset($_POST['orderby'])) $_POST['orderby'] = "";
+         if (!isset($_POST['orderby'])) $_POST['orderby'] = "date";

          (省略)

    }


結果は・・・。
A条件なしの一覧
商品数16000件でも、1.4秒になりました。
1000件ずつ増やしていき、30000件までいっても2.1秒という早さに!
しかし、31000件になると、また途端に遅くなり約457秒もかかっってしまいました。

Bカテゴリ指定の一覧
商品数1000件で0.9秒
商品数2000件で8.6秒
商品数3000件で19.9秒
商品数4000件で33.8秒
商品数5000件で54.0秒かかった。
ソート順を指定しないときと比べて若干早くなっていますが、ほとんど変わりませんでした。
単純な一覧では30000件まで問題なく表示できるようになりましたが、肝心のカテゴリ検索は遅いままです。もっと何か工夫できないでしょうか。
(3)PostgreSQLのチューニング
PostgreSQLの設定を変更することで、パフォーマンスを向上させることができないか試してみました。
※実験で使用したサーバーはCentOS 5.3でしたので、PostgreSQLの設定ファイルは「/var/lib/pgsql/data/postgresql.conf」になります。
注意:PostgreSQLの設定を変更した場合、PostgreSQLの再起動が必要になります。
今回は、random_page_costの設定値を変更してみました。
デフォルトの設定値が「4」のところを「3」に変更しました。
その結果・・・。
A条件なしの一覧
31000件の場合も1秒程度で表示されるようになりました。
しかし、32000件になると約420秒とまたまた遅くなってしまいました。
Bカテゴリ指定の一覧
4万件まで増やしても、1.2秒くらいで表示されるようになりました。
今回はそれ以上商品数を増やしませんでしたが、少なくとも4万件までなら、総商品数に関係なくサクサクと表示されるようです。
※今回の実験では、1カテゴリにつき商品1000件なのでカテゴリ指定で検索した場合、1000件の商品が表示されます。
指定したカテゴリの対象商品数が多い場合、この設定でも表示時間は早くならないようです。
(例)1カテゴリの商品数を5000件にすると、全体の商品数が15000件くらいのときでも、150秒くらいかかってしまいました。

今回のレポートはここまでです。

3000件くらいまではノーマルEC-CUBEとPostgreSQLのパラメタチューニングでいけそうです。上手にチューニングすればもうちょいいけるのかもしれません。

それ以上の領域は、ノーマルでは無理っぽい、というのが今のところの印象です。(2)の例のように、何かの機能を犠牲にするようなチューニングも、場合によっては検討の余地ありだと思います。(とりあえず手っ取り早いので。。)


2009/06/30 追記
EC-CUBEは商品数が多いとつらくなってしまう、もっと根本的な理由があるのを見落としていました。
PostgreSQLに詳しい方はこのページを良く見れば気がついたことと思います。

その2を見てください

大量商品登録ツール

大量商品登録ツール