自分が現場で学んだ事の一つに
データを一括取得した後に関数などでソートするより、取得の段階でSQLにて条件で絞った方がいい
という事があります。
まあ、普通に考えて100万件データを取得してソートして結果10万になるのと、SQLの段階で絞って10万件取得するのとでは後者の方が「処理速度」や「メモリの消費」の観点で効率がいいのはなんとなくわかりますよね。
でも、実際に比較したわけではないので、試しに検証してみましょう!という事で検証してみたいと思います。興味がある人は自分で実施してみてはいかがでしょうか。
実行環境
- macOS (Sequoia 15.1.1)
- PHP 8.3.12
- MySQL 9.0.1
①検証用データを格納するテーブルの作成
とりあえずカラム数が少ないと検証として難しいので、一旦6つほどカラムを持ったテーブルを作成します。
CREATE TABLE test (
id INT AUTO_INCREMENT PRIMARY KEY,
value INT NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
status ENUM('active', 'inactive') DEFAULT 'active'
);
②適当なテストデータを挿入
10万件ほどテストデータを挿入してみます。
SET @n := 0;
INSERT INTO test (value, name, status)
SELECT FLOOR(RAND() * 1000), CONCAT('Name', @n := @n + 1), IF(@n % 2 = 0, 'active', 'inactive')
FROM (SELECT 1 FROM information_schema.tables LIMIT 100000) AS numbers;
③検証用のPHPファイルを2つ作成
今回の条件は以下のようにします。
◯valueが500以上のものを取得する。
これを元に、
(1)配列関数を使用して取得
(2)SQLで最初から絞り込んで取得
のパターンに分けてソースコードを作成します。
※今回はmysqliを使用します。DB情報は自身のローカルの情報に合わせてください。
(1)配列関数を使用して取得
test1.php
<?php
$start_time = microtime(true);
// データベース接続
$conn = new mysqli("localhost", "root", "password", "db_name");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// 全データを取得
$result = $conn->query("SELECT * FROM test");
// 配列にデータを格納
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
// 配列関数で条件を絞り込み
$data = array_filter($data, function($row) {
return $row['value'] > 500;
});
// 絞り込んだ結果をインデックス付き配列に戻す
$data = array_values($data);
$conn->close();
// 処理時間の計測
$end_time = microtime(true);
echo "配列関数を使用して取得";
echo "取得件数: ".count($data)."件\n";
echo "PHPで条件を絞る場合の処理時間: " . ($end_time - $start_time) . "秒\n";
echo "メモリ使用量: " . memory_get_peak_usage(true) . "バイト\n";
?>
(2)SQLで最初から絞り込んで取得
test2.php
<?php
$start_time = microtime(true);
// データベース接続
$conn = new mysqli("localhost", "root", "password", "db_name");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// SQLで条件を絞る
$result = $conn->query("SELECT * FROM test WHERE value > 500");
// データを配列に格納
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
$conn->close();
// 処理時間の計測
$end_time = microtime(true);
echo "取得件数: ".count($data)."件\n";
echo "SQLで条件を絞る場合の処理時間: " . ($end_time - $start_time) . "秒\n";
echo "メモリ使用量: " . memory_get_peak_usage(true) . "バイト\n";
?>
④実際に実行
test1.phpとtest2.phpを保存したパスに移動して、各スクリプトを実行します。
※自分はDesktopに保存しました。
実行結果
(1)配列関数を使用して取得
処理時間:0.2064秒
メモリ使用量:82.32MB
(2)SQLで最初から絞り込んで取得
処理時間:0.1138秒
メモリ使用量:39.85MB
結論:SQLの方が処理時間・メモリ使用量ともに約2倍ほどの効率が良い
※データ数や構造、使用する関数によって多少前後するので、ご理解ください。