php4とPostgreSQLでPreparedStatement

2005/08/29 12:59

※ 商品のリンクをクリックして何かを購入すると私に少額の報酬が入ることがあります【広告表示】

hibernateがTorqueに比べて勝っている点は、唯一PreparedStatementを利用している点だ。

という職場でのやりとりから、rhacoのO/RはPreparedStatementを使用してみようと調査。

PreparedStatementを利用する利点は、主に二つ(あとは知らない)

php5ではphpの機能としてPreparedStatementが導入された模様ですが、php5を使う理由はどこにもない(だって、phpの利点は大抵のレンタルサーバで使えることでしょ?interfaceが欲しい?リフレクションが欲しい?php5は自分でインストールするから?=>他の言語を検討すれば?)。

php4にはPreparedStatementの機能がないので、自分で実装するしかない。

PostgreSQLのSQL文でPREPAREという物があるので、これが使えそう。

PREPARE plan_name [ (datatype [, ...] ) ] AS statement
EXECUTE plan_name [ (parameter [, ...] ) ]

pg_execを二回投げて一つのSQL文が実行できるというもの。

次のような特徴があるため、名前の管理が必要になる。

また、PREPAREでdatatypeを指定する必要があるので、JavaのPreparedStatementと同様に、ps->setInt(1, $value);のような型を指定するようなメソッドが無いとつらそう。

つまり、PreaparedStatementというクラスを作成して、SQL文とplan_nameと各引数となる値のhashオブジェクトを持たせることになる。

はたして、ここまでコストをかけて速くなるのだろうか?

簡単なテーブルにデータを1万行インサートしてみた所、案の定下記のようになった。

#planの生成にコストのかかるSQLに効果的なのはわかっるけど・・・

もう少し様々な条件でのテストと、PreparedStatementクラスのリファクタリングに励んでみよう。 以下、テストのガワ。

  <?
  require_once("config.php");
  require_once("RhacoModel/RDBConnection.php");
  require_once("test/UnitBench.php");

  class Test4 extends UnitBench {
    var $db;
    var $sql;
    var $name;
    var $ps;

    function benchPreparedStatement() {
      $this->db = RDBConnection::getConnection();
      $this->sql = "INSERT INTO pre_test (no, memo) values ($1, $2) ;";
      $this->name = "insert_pre_test";
      $this->ps = $this->db->createStatement($this->name, $this->sql);
      for($i = 0;$i < 10000;$i++) {
        $this->ps->clear(); //値のhashのみクリア
        $this->ps->setInt(1, $i);
        $this->ps->setText(2, sprintf("test(%s)", $i));
        $this->ps->executeQuery(); //初回のみPREPARE文の組み立てと実行
      }
    }

    function benchRawSql() {
      $this->db = RDBConnection::getConnection();
      for($i = 0;$i < 10000;$i++) {
        $memo = sprintf("test(%s)", $i); //見やすいようにばらしてあります
        $rawSql = sprintf("INSERT INTO pre_test (no, memo) values (%s, '%s') ;", $i, $memo);
        $this->db->executeQuery($rawSql); //ただ実行するのみ!
      }
    }
  }
  $test = new Test4();
  ?>

Prev Entry

Next Entry