FuelPHP1.5.3でViewに渡すデータが多い場合のパフォーマンス

軽量なPHP FrameworkのFuelPHP1.5.3を利用することになったのでお勉強開始。itemsテーブルをTASKのfromdbでscaffold。

php oil refine fromdb:scaffold --force items

ここで生成されたスケルトンをカスタムして、一般的なDBデータを一覧表示を実装するテストを実施してみたが、1ページあたりの表示可能件数を指定できるようになったところで100,300,500件の表示をすると結構応答が遅いことに気がついた。

サーバースペックはCPU AtomD525・Memory 4GB・SSDなので、さほど速いPCでもないが、このくらいで遅くなるのもちょっと変だなと調べてみた。

FuelPHP Profilerの結果

FuelPHPに付属のProfilerをONにしてみて300件のリストを表示してみると、時間がかかっているところがあるようだ。

しかし、Profilerが優れているなぁ。

  • fuel/app/config/config.php
'profiling'  => true,
FuelPHP profiler

XHProfによるプロファイル

次にもっと詳細にプロファイリングするためにXHProfを仕込んで実行してみたところ、2箇所が怪しい。 1つ目は Fuel\Core\Html::anchor 。

できたてのViewはリストの1つ1つの項目でHtml::anchorをCallして、view,edit,deleteのanchor要素をつくるので、Html::anchorは行数×3回呼ばれる。そりゃ遅いしHTMLのデータ量も多くなる。これは全部リンクを作る必要は無いので外す。

すると若干軽くなった。

もう1つはoutput_filterに指定されている、Security::htmlentities。

どうもViewに送られるデータを全部自動的にSecurity::htmlentitiesでフィルターかけるようだ。

これは何となく重そうなので、Security::htmlentitiesを外す方法を調べてみた。

Security::htmlentities を外してみる実験

Security::htmlentitiesを外してテストしてみる。

※実運用ではありません!実運用では何らかの方法で出力を無害化必要!

まずは、configなどはそのままの状態で、Security::htmlentitiesが有効な場合。

fuelphp_many_list_security

500件表示で、7.12秒かかる。 次に、 fuel/app/config/config.php で Security::htmlentitiesが全くかからないようにしてみる。

/**
 * Whether to automatically filter view data
 */
'auto_filter_output'  => false
fuelphp_many_list_auto_filter_output_false

500件表示で、1.52秒!改善している。 同じようなものだが、‘Security::htmlentities’をフィルタから外した。

/**
 * This output filter can be any normal PHP function as well as 'xss_clean'
 *
 * WARNING: Using xss_clean will cause a performance hit.
 * How much is dependant on how much input data there is.
 */
//'output_filter'  => array('Security::htmlentities'),
'output_filter'  => array(),
fuelphp_many_list_output_filter_none

500件表示で、1.53秒!
まぁ、そうでしょう。
今度は、output_filterはONだが、コントローラーでViewにデータを渡すときにフィルタされないようにset_safeで渡してみた。

$items = Model_Item::find()
            ->rows_offset($offset)
            ->rows_limit($pagination->per_page)
            ->get();

//$data['items'] = $items;

$this->template->content = View::forge('items/index', $data);
$this->template->content->set_safe('items', $items);"
fuelphp_many_list_setfalse

500件表示で、1.54秒!

あと、config の whitelisted_classes を使う方法もあるかもしれない(未調査)。

FuelPHPで、データが多くパフォーマンスが悪い場合は、Security::htmlentities以外の方法で出力をエスケープするのも1つの方法のようだ。