php4とPostgreSQLでPreparedStatement
2005年08月29日(月) 12:59
hibernateがTorqueに比べて勝っている点は、唯一PreparedStatementを利用している点だ。
という職場でのやりとりから、rhacoのO/RはPreparedStatementを使用してみようと調査。
PreparedStatementを利用する利点は、主に二つ(あとは知らない)
php4にはPreparedStatementの機能がないので、自分で実装するしかない。
PostgreSQLのSQL文でPREPAREという物があるので、これが使えそう。
次のような特徴があるため、名前の管理が必要になる。
つまり、PreaparedStatementというクラスを作成して、SQL文とplan_nameと各引数となる値のhashオブジェクトを持たせることになる。
はたして、ここまでコストをかけて速くなるのだろうか?
簡単なテーブルにデータを1万行インサートしてみた所、案の定下記のようになった。
#planの生成にコストのかかるSQLに効果的なのはわかっるけど・・・
以下、テストのガワ。
という職場でのやりとりから、rhacoのO/RはPreparedStatementを使用してみようと調査。
PreparedStatementを利用する利点は、主に二つ(あとは知らない)
- SQL Injectionに対して強くなる
- 同じ文のプロパティ違いSQLは劇的に速くなる(可能性がある)
php4にはPreparedStatementの機能がないので、自分で実装するしかない。
PostgreSQLのSQL文でPREPAREという物があるので、これが使えそう。
PREPARE plan_name [ (datatype [, ...] ) ] AS statementpg_execを二回投げて一つのSQL文が実行できるというもの。
EXECUTE plan_name [ (parameter [, ...] ) ]
次のような特徴があるため、名前の管理が必要になる。
- 1セッションの間 PREPARE は有効。
- ただし、plan_nameは1セッションの間に重複して宣言することは出来ない。
- DEALLOCATEでplan_nameを解放することは出来るが、宣言していない物を解放しようとするとエラーとなる。
つまり、PreaparedStatementというクラスを作成して、SQL文とplan_nameと各引数となる値のhashオブジェクトを持たせることになる。
はたして、ここまでコストをかけて速くなるのだろうか?
簡単なテーブルにデータを1万行インサートしてみた所、案の定下記のようになった。
#planの生成にコストのかかるSQLに効果的なのはわかっるけど・・・
- PreparedStatementを利用した物 => 28秒
- sprintfしたSQLを投げまくった物 => 24秒
以下、テストのガワ。
<?
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();
?>
