PHPのfor文で、配列の数を評価するときの違いによるベンチマークを取ってみた
きっかけは仕事でコードレビューをしていたときに、以下のようなfor文をみたこと。
for ($i = 0, $count = count($data); $i < $count; $i++) { // 何らかの処理 }
$count
はfor文の条件判定でしか使用されていなかったので、そのときは変数を使わずに直接書けばいいのにと思った。
for ($i = 0; $i < count($data); $i++) { // 何らかの処理 }
一方でそれぞれのパフォーマンスが気になったので、模したコードで確認してみた。
確認環境のOSはCentOS 7.1。
$ cat /etc/redhat-release CentOS Linux release 7.1.1503 (Core)
phpは5.6.11。
$ php -v PHP 5.6.11 (cli) (built: Jul 12 2015 20:13:00) Copyright (c) 1997-2015 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies
ベンチマーク取得のコードは下記のエントリーのコードを使用した。
実際に書いたコード。
以下は実行結果の一つ。
$ php bench_count.php 1 $count : 0.0000 sec @ 0.0000 sec (336.00%) count() : 0.0000 sec @ 0.0000 sec (100.00%) 1 $count : 0.0000 sec @ 0.0000 sec (100.00%) count() : 0.0000 sec @ 0.0000 sec (123.53%) 10 $count : 0.0000 sec @ 0.0000 sec (100.00%) count() : 0.0000 sec @ 0.0000 sec (160.17%) 100 $count : 0.0003 sec @ 0.0000 sec (100.00%) count() : 0.0004 sec @ 0.0000 sec (165.26%) 1000 $count : 0.0027 sec @ 0.0000 sec (100.00%) count() : 0.0048 sec @ 0.0000 sec (180.65%) 10000 $count : 0.0277 sec @ 0.0000 sec (100.00%) count() : 0.0454 sec @ 0.0000 sec (163.59%) 100000 $count : 0.2720 sec @ 0.0000 sec (100.00%) count() : 0.4506 sec @ 0.0000 sec (165.69%) 1000000 $count : 2.7292 sec @ 0.0000 sec (100.00%) count() : 4.5232 sec @ 0.0000 sec (165.73%)
1回から1000000回まで、実行回数を変えてそれぞれのパフォーマンスを相対的に確認する。 1回実行のテストを2回行っているのは、その内容に関わらずどうしても最初に実行したテストが遅くなったため。
何回か確認したが関数を毎回評価する方が遅く、その差は大体1.2倍から2倍ほど。 変数に比べて関数の方が遅いのは予想していたものの、相対的に見てここまで差があると変数にしたいのもわかる。
参照整合性制約で参照されるテーブルから、定義したテーブルと制約名を取得するSQL
以下はFOO
テーブルのカラムを参照するテーブルと制約名を取得するSQL。
SELECT uc.table_name, uc.constraint_name FROM user_constraints uc JOIN user_constraints ruc ON ruc.owner = uc.r_owner AND ruc.constraint_name = uc.r_constraint_name WHERE uc.constraint_type = 'R' AND ruc.table_name = 'FOO' ;
使用するのはuser_constraintsビュー。
constraint_type
がR
となっているのが参照整合性制約の定義。これは該当テーブル名と制約名、参照先テーブルの一意制約名からなる。
参照整合性制約の定義を取得するビュー(uc
)と、参照先の一意制約の定義を取得するするビューを(ruc
)内部結合して、該当の定義を取得する。
参考
Oracleで特定テーブルの参照整合性制約を確認するSQL
今、Symfony2を使用した開発をしている。DBはOracle。
Symfony2のconsoleでORMの設定からSQLを作成することができる。利用しているDBの状況から最新にするために必要なSQLを作成できるので便利。しかし、その作成に時間がかなりかかるため、その調査をした。
実行ログをみると参照整合性制約を抽出するSQLに時間がかかっていたため、SQLを書き換えて改善されるか試してみた。そのとき作成したSQLが以下。
SELECT uc.constraint_name, uc.delete_rule, uc.search_condition, ucc.column_name, ucc.position, r_ucc.table_name r_table_name, r_ucc.column_name r_column_name FROM user_constraints uc JOIN user_cons_columns ucc ON ucc.owner = uc.owner AND ucc.constraint_name = uc.constraint_name JOIN user_cons_columns r_ucc ON r_ucc.owner = uc.r_owner AND r_ucc.constraint_name = uc.r_constraint_name AND r_ucc.position = ucc.position WHERE uc.constraint_type = 'R' AND uc.table_name = 'FOO' ORDER BY uc.constraint_name ASC, ucc.position ASC ;
確認するために2つのビューを使用する。user_constraints
は、テーブルに定義された制約を示すビューでuser_cos_columns
はその制約で使用しているカラムを示すビュー。
user_constraints.constraint_type
は当該制約の種別でR
は参照整合性を意味する。参照整合性制約の場合、user_constraints.owner
とuser_constraints.constraint_name
が参照元の制約であり、参照先の制約はuser_constraints.r_owner
とuser_constraints.r_constraint_name
。
それぞれのカラムをuser_cons_columns
の該当カラムと内部結合して、それぞれのテーブル名とカラム名を取得した。
ちなみに上記のSQLで試したところ元のSQLよりは改善されたが、それでも実行には数秒かかった。どうやらuser_constraints
をselectするだけでも時間がかかっているようだった。