検証内容
PHP7へと環境を刷新しているので、職場のMySQL5.7に入ってた6500件ほどのデータを使って検証。
前もってselectをしておいたのでMySQLのバッファに全データが乗っているはず。
検索結果を全行返却する処理を5000回試行して、かかった平均・合計時間を計測した。
ソースコード(テーブル定義だけ伏せたやつ)
<?php
$pdo = new PDO('mysql:host=localhost;dbname=hoge_db', 'root', 'pass');
// 性能検証用の処理
function profile($text, $f) {
$testCount = 5000; // 試行回数
$totalTime = .0;
for($i = 0; $i < $testCount; ++$i){
$start = microtime(true);
$rows = $f();
$end = microtime(true);
$time = $end - $start;
$totalTime += $time;
}
$avg = $totalTime / $i;
printf("$text [ avg ] %1.6f [total] %3.6f \n", $avg, $totalTime);
}
// fetchで利用するテーブルマッピング用のクラス
class FetchClass {
public $pk_1; // int
public $pk_2; // int
public $param_1; // int
public $param_2; // int
public $param_3; // int
public $param_4; // int
public $timestamp_1; // timestamp
public $timestamp_2; // timestamp
}
// 1 : 行単位読み取り + 連想配列で受け取るモード
profile("fetch ASSOC", function() use ($pdo) {
$st = $pdo->prepare('select * from hoge_table');
$st->setFetchMode(PDO::FETCH_ASSOC);
$st->execute();
$rows = [];
while($row = $st->fetch()){
$rows[] = $row;
}
return $rows;
});
// 2 : 行単位読み取り + stdClassで受け取るモード
profile("fetch OBJ ", function() use ($pdo) {
$st = $pdo->prepare('select * from hoge_table');
$st->setFetchMode(PDO::FETCH_OBJ);
$st->execute();
$rows = [];
while($row = $st->fetch()){
$rows[] = $row;
}
return $rows;
});
// 3 : 行単位読み取り + 指定クラスで受け取るモード(各行を新規インスタンス生成)
profile("fetch CLASS", function() use ($pdo){
$st = $pdo->prepare('select * from hoge_table');
$st->setFetchMode(PDO::FETCH_CLASS, 'FetchClass');
$st->execute();
$rows = [];
while($row = $st->fetch()){
$rows[] = $row;
}
return $rows;
});
// 4 : 行単位読み取り + 指定クラスで受け取るモード(各行を既存インスタンスへ貼り付け)
profile("fetch INTO ", function() use ($pdo){
$st = $pdo->prepare('select * from hoge_table');
$fetchCls = new FetchClass;
$st->setFetchMode(PDO::FETCH_INTO, $fetchCls);
$st->execute();
$rows = [];
while($row = $st->fetch()){
// 他と同じ結果となるようクローンして格納
// ここで処理して編集した結果を返すなら違う結果になるかも
$rows[] = clone $row;
}
return $rows;
});
// 5 : 全行一括読み取り + 連想配列で受け取るモード
profile("fetchAll ASSOC", function() use ($pdo) {
$st = $pdo->prepare('select * from hoge_table');
$st->setFetchMode(PDO::FETCH_ASSOC);
$st->execute();
$rows = $st->fetchAll();
return $rows;
});
// 6 : 全行一括読み取り + stdClassで受け取るモード
profile("fetchAll OBJ ", function() use ($pdo) {
$st = $pdo->prepare('select * from hoge_table');
$st->setFetchMode(PDO::FETCH_OBJ);
$st->execute();
$rows = $st->fetchAll();
return $rows;
});
// 7 : 全行一括読み取り + 連想配列で受け取るモード(各行を新規インスタンス生成)
profile("fetchall CLASS", function() use ($pdo){
$st = $pdo->prepare('select * from hoge_table');
$st->setFetchMode(PDO::FETCH_CLASS, 'FetchClass');
$st->execute();
$rows = $st->fetchAll();
return $rows;
});
// 8 : fetchAllで既存インスタンスを使いまわすFETCH_INTOは不可能なので計測なし
結果
No | 処理 | 返却方法 | 平均(秒) | 合計(秒) | 倍率(切り上げ) | |
---|---|---|---|---|---|---|
1 | fetch ASSOC | 連想配列 | 0.015279 | 76.392952 | 最速 | 1倍(基準) |
2 | fetch OBJ | stdClass | 0.016582 | 82.908913 | 遅い | 1.09倍 |
3 | fetch CLASS | 指定クラス(newする) | 0.016311 | 81.553230 | 遅い | 1.07倍 |
4 | fetch INTO | 指定クラス(既存インスタンス) | 0.015970 | 79.849632 | 中間 | 1.05倍 |
No | 処理 | 返却方法 | 平均(秒) | 合計(秒) | 倍率(切り上げ) | |
---|---|---|---|---|---|---|
5 | fetchAll ASSOC | 連想配列 | 0.011633 | 58.164605 | 最速 | 1倍(基準) |
6 | fetchAll OBJ | stdClass | 0.012816 | 64.082171 | 遅い | 1.10倍 |
7 | fetchall CLASS | 指定クラス(newする) | 0.012597 | 62.984455 | 遅い | 1.09倍 |
連想配列(ASSOC) > 指定クラス(INTO) > 指定クラス(CLASS) == stdClass(OBJ)
この順番で早かったです。
あと全行返却するならfetchAllを使うこと。