3

テストがより読みやすくなるように更新されました。すべて100xforeachループ内で実行されます。

テストクエリはSELECT*FROMschool_coursesです。

誰もが次のことに関して「既成概念にとらわれない」フィードバックを提供できますか。

a)PHP ActiveRecord ORMが以下の結果に従って同じクエリを実行するのに4秒かかるのはなぜですか?

b)これが、クエリの方法を比較するための実用的なベンチマークなのか、それとも架空のベンチマークなのか。

c)より明確な画像を得るために他の方法(テストケース)を試す(またはこれらの方法を修正する)必要がありますか?

結果(PDOおよびMySQLiを使用)

Iterations: 100

PHP (config file)
Base Time: 5.793571472168E-5
Gross Time: 0.055607080459595
Net Time: 0.055549144744873

PHP ActiveRecord ORM
Base Time: 5.2213668823242E-5
Gross Time: 4.1013090610504
Net Time: 4.1012568473816

MySQL (standard)
Base Time: 5.1975250244141E-5
Gross Time: 0.32771301269531
Net Time: 0.32766103744507

CodeIgniter (Active Record)
Base Time: 5.1975250244141E-5
Gross Time: 0.28282189369202
Net Time: 0.28276991844177

MySQLi
Base Time: 5.1975250244141E-5
Gross Time: 0.20240592956543
Net Time: 0.20235395431519

PDO
Base Time: 5.2928924560547E-5
Gross Time: 0.17662906646729
Net Time: 0.17657613754272

テスト

// Benchmark tests
$runs = 100;

// PHP (config file)
for ($i = 0; $i < $runs; $i++) {
    $this->view_data['courses'] = course_info();
}

// PHP ActiveRecord ORM
for ($i = 0; $i < $runs; $i++) {
    $this->view_data['courses'] = Course::all();
}

// mysql_* (MySQL standard; deprecated)
for ($i = 0; $i < $runs; $i++) {
    $sql = mysql_query('SELECT * FROM school_courses') or die(mysql_error());
    while ($row = mysql_fetch_object($sql)) {
        array_push($this->view_data['courses'], $row);
    }
}

// CodeIgniter (Active Record)
for ($i = 0; $i < $runs; $i++) {
    $this->view_data['courses'] = $this->db->get('school_courses');
}

// mysqli_* (MySQLi)
for ($i = 0; $i < $runs; $i++) {
    $res = $mysqli->query('SELECT * FROM school_courses');
    while ($row = $res->fetch_object()) {
        array_push($this->view_data['courses'], $row);
    }
}

// PDO
for ($i = 0; $i < $runs; $i++) {
    foreach($conn->query('SELECT * FROM school_courses') as $row) {
        array_push($this->view_data['courses'], $row);
    }
}
4

3 に答える 3

2

したがって、同時接続のベンチマーク時にPHP ActiveRecord ORMが非常に多くのオーバーヘッドを導入する理由は、返される各結果が新しいModelオブジェクトをインスタンス化するという事実によるものです。これはこのORMライブラリの使用に不可欠であり、ライブラリ全体をオーバーホールせずに変更を加える合理的な方法はわかりません。

これが私が見つけたものです:

Tableクラスのfind_by_sql()メソッド内には、次のものがあります。

    $sth = $this->conn->query($sql,$this->process_data($values));

    while (($row = $sth->fetch()))
    {
        $model = new $this->class->name($row,false,true,false);

        if ($readonly)
            $model->readonly();

        if ($collect_attrs_for_includes)
            $attrs[] = $model->attributes();

        $list[] = $model;
    }

具体的には、動的モデルのインスタンス化であるnew $ this-> class-> name()がオーバーヘッドの原因であり、たとえば、フェッチされた結果ごとに約0.004の重みがあります。

これを取得して、現在のレコード数を掛けます(10レコード= 0.04)。これに同時接続の数、たとえば100を掛けると、予測可能なボトルネックの問題が発生します。

100人のユーザー(仮想的に言えば)が10個のレコードを含むテーブルに同時にアクセスする場合は4秒。

この時点で、フェッチされるレコードの数が、このライブラリがすべてのレコードのモデルクラスをインスタンス化する方法が原因で、ボトルネックの問題を引き起こす可能性があることを心配する必要がありますか?

繰り返しになりますが、これはすべて、ORMの適切な使用を前提として、現実の世界では決して存在しないか、問題を提示する可能性のある、この時点での架空のスピーチである可能性があります。そして、これらのテストまたは結論が不正確でない限り、ここでシミュレートしようとしているのは、たとえば100、1,000、および10,000のアクティブなオンサイト訪問者のトラフィック負荷です。

つまり、別のコースを追加しない場合(制限10)、たとえば、10,000人の訪問者がコースページを閲覧すると、他の人がページから移動するまで400秒(6.67分)の待機時間が発生しますか?その場合、私は自分自身の答えを発見し(したがって、この投稿)、別のORMを見つけるか、ケースバイケースでリファクタリングに頼ることを検討します。

これは、トラフィックの負荷をベンチマークおよびシミュレートするための最も適切な方法ですか?

追加リソース

abツールを使用してApacheストレステストを行う方法 https://wiki.appnexus.com/display/documentation/How+to+Apache+Stress+Test+With+ab+Tool

于 2012-11-13T20:52:30.530 に答える
1

推奨事項の書き換え:

残忍に聞こえたくはありませんが、mysql_()について知っていることをすべて忘れた場合は、将来的に多くの頭痛の種を減らすことができ、現在の慣行についていくことができます。今日の基準では、正直言ってゴミです。dbインターフェースとしてmysqli_またはPDOを調べてください。

mysqli_: http: //us2.php.net/manual/en/book.mysqli.php

PDO: http: //us2.php.net/manual/en/book.pdo.php

その後、ベンチマークを報告します...

于 2012-11-13T18:23:16.237 に答える
0

あなたの単純なクエリは実際には公正なテストではありません。ORMは問題なく、そのような単純なクエリに対してかなり競争力があります。ORMが非効率的なクエリを作成し、それらをバイパスする必要がなくなるのは、より複雑なもの(つまり、LEFT JOIN)です。ORMは、SQLを知っている人が書いた生のSQLよりも常に遅くなります。もちろん、SQLを知ることが重要です。

ORMを検討している場合は、Doctrineを試してみてください。私は(まったく)ファンのORMではありませんが、それは世の中で最も人気のあるPHPORMです。

一括挿入は、一部のORMとDB抽象化レイヤーがつまずく別の領域でもあります。バルクインサートを使用できることを認識する代わりに、ループ内でシングルインサートを実行します。これにより、速度が低下するだけでなく、MyISAMでテーブルロックの問題が発生します。おそらく、一括挿入テストを追加して、可能であれば各DBレイヤーに挿入クエリを生成させます。

テスト方法が明らかにすることは、多くの反復にわたって、各DBアクセス方法のオーバーヘッドが合計されることです。クエリのオーバーヘッドを完全に排除し、代わりに「SELECTVERSION()」を使用することをお勧めします。

于 2012-11-14T00:14:50.867 に答える