7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[PHP7]PDOのfetchモード速度比較

Last updated at Posted at 2018-02-06

検証内容

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を使うこと。

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?