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,
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が有効な場合。
500件表示で、7.12秒かかる。 次に、 fuel/app/config/config.php で Security::htmlentitiesが全くかからないようにしてみる。
/**
* Whether to automatically filter view data
*/
'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(),
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);"
500件表示で、1.54秒!
あと、config の whitelisted_classes を使う方法もあるかもしれない(未調査)。
FuelPHPで、データが多くパフォーマンスが悪い場合は、Security::htmlentities以外の方法で出力をエスケープするのも1つの方法のようだ。