もうZend Framework 1(ZF1)の話はいいやって感じだけど一応メモ。
ZF1を使ってDBへのアクセスを実現するには、通常はZend_Db_Table_Abstractクラスを継承したモデルクラスを作って実現すると思うじゃないですか。
<?php require_once 'Zend/Db/Table/Abstract.php'; class Model_Hoge extends Zend_Db_Table_Abstract { protected $_name = 'hoge'; }
で、例えばデータの取得は以下のような感じ。
$query = $hoge->select(); $rows = $hoge->fetchAll($query); $res= array(); while ($rows->valid()) { $row = $rows->current(); $res[$row->id] = $row->name; $rows->next(); }
でも、これだと、Zend_Db_Table_Rowset_Abstractが返された瞬間に全レコードのデータがメモリに載るので、件数が多かったりするとメモリアロケーションエラーが発生する。
そんなわけで「Zend Framework カーソル」なんて検索すると以下のページがヒットしたりするわけなんだが。
- Manual - Documentation - Zend Framework
Statement?DB Adapter? なんか嫌な予感がした。
先のモデルクラスをベースにすると、以下のように書かないと、大量データの処理の際には使い物にならないという。
$query = $hoge->select(); $stmt = $hoge->getAdapter()->query($query->__toString()); $res = array(); while (($row = $stmt->fetch()) !== false) { $res[$row["id"]] = $row["name"]; }
もう、Zend_Db_Table_Rowset_AbstractやZend_Db_Table_Row_Abstractの恩恵一切なし・・・
ついでだったので、INSERTがクソ遅いという問題についても調べてみた。
元のコードはこんな感じ。
$start = time(); for ($i = 10000; $i < 11000; ++$i) { $data = array( "id" => $i, "name" => "hhelibex-{$i}", ); $hoge->insert($data); } echo('insert time:' . (time() - $start)); $start = time(); try { for ($i = 10000; $i < 11000; ++$i) { $data = array( "name" => "HHeLiBeX-{$i}", ); $where = array( "id = ?" => $i, ); $hoge->update($data, $where); } } catch (Exception $e) { echo '<pre>' . $e->__toString() . '</pre>'; } echo('update time:' . (time() - $start)); $start = time(); try { for ($i = 10000; $i < 11000; ++$i) { $where = array( "id = ?" => $i, ); $hoge->delete($where); } } catch (Exception $e) { echo '<pre>' . $e->__toString() . '</pre>'; } echo('delete time:' . (time() - $start));
これを実行すると、環境にもよるが(だいぶ前のLet's Note上のCentOS 7なので)、
insert time:40 update time:41 delete time:37
で、こんなふうに書き換えてみた。
<?php require_once 'Zend/Db/Table/Abstract.php'; class Model_Hoge extends Zend_Db_Table_Abstract { protected $_name = 'hoge'; public function getTableName() { return $this->_name; } } $start = time(); try { for ($i = 10000; $i < 11000; ++$i) { $data = array( "id" => $i, "name" => "hhelibex-{$i}", ); $hoge->getAdapter()->insert($hoge->getTableName(), $data); } } catch (Exception $e) { echo '<pre>' . $e->__toString() . '</pre>'; } echo('insert time:' . (time() - $start)); $start = time(); try { for ($i = 10000; $i < 11000; ++$i) { $data = array( "name" => "HHeLiBeX-{$i}", ); $where = array( "id = ?" => $i, ); $hoge->getAdapter()->update($hoge->getTableName(), $data, $where); } } catch (Exception $e) { echo '<pre>' . $e->__toString() . '</pre>'; } echo('update time:' . (time() - $start)); $start = time(); try { for ($i = 10000; $i < 11000; ++$i) { $where = array( "id = ?" => $i, ); $hoge->getAdapter()->delete($hoge->getTableName(), $where); } } catch (Exception $e) { echo '<pre>' . $e->__toString() . '</pre>'; } echo('delete time:' . (time() - $start));
結果は。
insert time:16 update time:16 delete time:14
半分以下にはなった。