4

現在、PDO を使用する PHP でアプリケーションを開発しています。CSVファイルを読み込み、データベースのレコードをチェックし、更新、削除などを行うインポートを書いています....

私が気付いたのは、このスクリプトで使用されているメモリが非常に多く、クエリの実行方法に関係しているように見えることです。CSV の各行に対して実行されるクエリの例については、以下を参照してください。

$qry = "SELECT * FROM company WHERE id = 1";
$sth = $this->prepare($qry);
$sth->execute();
$sth->setFetchMode(PDO::FETCH_INTO, new Company());
$sth->fetch();

上記の場合、memory_get_peak_usage() = 6291456

以下を使用する場合:

$qry = "SELECT * FROM company WHERE id = 1";
$sth = $this->prepare($qry);
$sth->execute();
$sth->setFetchMode(PDO::FETCH_CLASS, "Company");
$sth->fetch();

上記の場合、memory_get_peak_usage() = 524288

ご覧のとおり、その差はかなり大きいです。

私は3つの質問があると思います..

  1. PHP 5.3.5 で PDO::FETCH_OBJ を使用するとメモリ リークが発生しますか?
  2. FETCH_OBJ とは対照的に FETCH_CLASS の使用に違いはありますか?
  3. 他の誰かが同じ問題を経験しましたか?

Company クラスは単純です。

class Company {
    function __construct(){}
    /**classvars**/
    public $_tablename = 'company';
    public $transient;
    public $id;
    public $name;
    /**endclassvars**/
} 
4

3 に答える 3

3

PHPの変更ログを見ると、5.3.4 に関連する修正があり、PDO でメモリ リークが修正されてFETCH_INTOいるようです。

あなたが言ったことから、はい、これがあなたが見ているバグだと思います。もちろん、解決策はアップグレードです。古いパッチ リリースに固執しても意味がありません。

これがあなたが目にしているバグではなくても、5.3.3 から現在までのバージョンで非常に多くの PDO 修正が行われています。少なくともそれらのいくつかがあなたに関連している可能性は十分にあると確信しています.

于 2013-01-23T14:53:21.323 に答える
2

:元の回答は、OPが変更される前に与えられましPDO::FETCH_OBJPDO::FETCH_INTO

その更新後、 を使用して動作を再現しようとしましたPHP 5.3.10-1ubuntu3.4。両方のフェッチ モード間でメモリ消費量に大きな違いはありません。大規模な MySQL テーブルと大規模な SQLite データベースを使用してテストしました。

@SDC が言及したように、バグは既知であり、5.3.5 以降に修正されました。(私が見たように、少なくとも 5.3.10 では)。

結論: PHP のバージョンをアップグレードする必要があります。


動作は興味深いものであり、調査する必要がありますがPDO::setFetchMode()、間違った方法で使用しています。$mode (最初のパラメーター) が PDO::FETCH_OBJ場合、 2 番目のパラメーターは必要ありません。2 番目のパラメータを使用すると、への呼び出しsetFetchMode()は失敗し (false を返す)、デフォルトのフェッチ モードFETCH_BOTHが使用されます。

有効にすると、次のエラーが表示されますPDO::ERRMODE_EXCEPTION

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $db->query('....');

// the following line will trigger an exception
$stmt->setFetchMode(PDO::FETCH_OBJ, new Company());

致命的なエラー: メッセージ「SQLSTATE[HY000]: 一般エラー: フェッチ モードでは余分な引数は許可されていません」を含む例外「PDOException」をキャッチできませんでした

結果行が特定のクラスのオブジェクトであることを期待している場合、それPDO::FETCH_CLASSが機能する試みです。PDO::FETCH_OBJタイプからオブジェクトを返しますStdClass

于 2013-01-23T14:06:20.207 に答える
0

FETCH_INTO: 既存のオブジェクト (新しい eg で作成されたオブジェクト) へのフェッチを意味します。

FETCH_CLASS: 新しいオブジェクトへのフェッチを意味します (コンストラクターはすべての行で呼び出されます)

Company クラスのコンストラクターに依存関係がある場合、それらはすべての行に対して呼び出されることに注意してください。したがって、コンストラクターには、DB接続を行う関数またはクラスを含めないでください。たとえば、単純な初期化のみ...

あなたの会社のクラスはどのように見えますか?

于 2013-01-23T14:42:11.943 に答える