PHPでデータベースを扱う際、ORMの使用が一般的になっています。
しかし、パフォーマンスを最大限に引き出したり、細かいデータ操作を行う場合には、直接SQL文を書くことが適しています。
この記事では、PHPでSQL文を効果的に管理し、実行する方法について説明します。
Python版については、以下の記事となります。
SQL文を利用する理由
データベースを操作する際、ORMの使用が主流となっています。
ORMを使えば、オブジェクト指向の概念でデータベースを扱うことができ、生産性が向上します。
しかし、ORMにも限界があります。
複雑なクエリや、データベース固有の機能を活用する必要がある場合、ORMでは対応しきれないことがあるのです。
そこで、SQL文を直接記述することを検討します。
SQL文を使えば、より細かな制御が可能になり、パフォーマンスの最適化にもつながります。
具体的には、以下のようなメリットがあります。
複雑なクエリの実行
ORMでは表現しきれない複雑なクエリも、SQLを直接記述することで実行できます。
複数のテーブルを結合したり、サブクエリを使ったりといった操作が可能です。
データベース固有の機能の活用
データベースには、それぞれ固有の機能があります。
例えば、PostgreSQLのウィンドウ関数やMySQLのフルテキストインデックスなど。
これらの機能をORMから利用するのは難しいですが、SQLを直接記述すれば活用できます。
と言っても、なるべくは固有のモノは使いたくないですけどね。
パフォーマンスの最適化
ORMは便利な反面、生成されるSQLが最適でない場合があります。
特に、大量のデータを扱う場合、わずかなクエリの違いが大きな性能差につながることもあり得ます。
SQLを直接記述することで、より効率的なクエリを実行できます。
柔軟性の確保
ORMを使うということは、ORMの規約に沿って開発を進めることになります。
しかし、プロジェクトによっては、その規約から外れた実装が必要になることもあるでしょう。
SQLを直接記述する選択肢を持っておけば、柔軟に対応できます。
とはいえ、SQLを直接記述するためには、SQLの知識が必要不可欠です。
開発チームのスキルセットを考慮する必要があります。
また、SQLを直接記述することで、コードの可読性が下がったり、メンテナンス性が悪化したりする恐れもあります。
したがって、ORMとSQLのバランスを取ることが重要です。
基本的にはORMを使いつつ、必要に応じてSQLを直接記述する、といった使い分けが理想的でしょう。
プロジェクトの要件や、開発チームの状況を踏まえて、適切な選択をすることが求められます。
ORMだけに頼るのではなく、SQLも活用できる柔軟性を持つことが、より良いデータベース操作につながるのです。
SQL文の管理方法
SQL文の管理方法は、Pythonの例と同様です。
クエリは1つのファイルに1つずつ格納し、それらを結合したファイルを用意します。
queries/ ├── get_user_by_id.sql ├── get_product_by_id.sql ├── insert_new_product.sql ├── update_user_email.sql └── delete_product_by_id.sql
各SQLファイルの内容や、結合したcombined_queries.sqlファイルの内容は、Pythonの例と同じです。
SQL文の実行方法
ここでは、PHPを用いて説明します。
combined_queries.sqlファイルからクエリを取得し、実行するクラスを作成します。
以下は、PHPコードの例です。
<?php
class Database {
protected $pdo;
public function __construct($dbPath) {
$this->pdo = new PDO("sqlite:$dbPath");
}
public function getQuery($queryName) {
$content = file_get_contents('combined_queries.sql');
$queryStart = strpos($content, "-- [$queryName]");
if ($queryStart === false) {
throw new Exception("Query '$queryName' not found.");
}
$queryEnd = strpos($content, "-- [", $queryStart + 1);
if ($queryEnd === false) {
$queryEnd = strlen($content);
}
$queryText = substr($content, $queryStart, $queryEnd - $queryStart);
$queryLines = explode("\n", $queryText);
// Remove empty lines and trim each line
$queryLines = array_map('trim', array_filter($queryLines));
// Find the last line that starts with "SELECT", "INSERT", "UPDATE", or "DELETE"
$query = '';
foreach (array_reverse($queryLines) as $line) {
if (preg_match('/^(SELECT|INSERT|UPDATE|DELETE)\s+/i', $line)) {
$query = $line;
break;
}
}
if (empty($query)) {
throw new Exception("Query '$queryName' is empty.");
}
return $query;
}
public function executeQuery($queryName, $params = []) {
$query = $this->getQuery($queryName);
$stmt = $this->pdo->prepare($query);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
function main() {
$db = new Database('database.db');
$queryName = 'get_user_by_id';
$userId = 1;
$result = $db->executeQuery($queryName, [$userId]);
echo "Result of $queryName: ";
print_r($result);
echo "\n";
$queryName = 'get_product_by_id';
$productId = 2;
$result = $db->executeQuery($queryName, [$productId]);
echo "Result of $queryName: ";
print_r($result);
echo "\n";
}
main();
?>
Database クラスは、getQuery関数とexecuteQuery関数を持ち、クエリの取得と実行を行います。
main関数では、get_user_by_idとget_product_by_idのクエリを実行し、結果を表示しています。
この例では、SQLiteデータベースを使用しています。適切なデータベース設定と、データの登録は、Pythonの例と同様に行います。
コードを実行した結果は、以下のようになります。
Result of get_user_by_id: Array
(
[0] => Array
(
[id] => 1
[name] => John Doe
[email] => john@example.com
)
)
Result of get_product_by_id: Array
(
[0] => Array
(
[id] => 2
[name] => Samsung Galaxy S21
[price] => 799.99
)
)
まとめ
PHPでSQL文を効果的に管理し、実行する方法について説明しました。
Pythonの例と同様に、1つのファイルに1つのクエリを格納し、それらを結合したファイルを用意することで、クエリの管理が容易になります。
また、直接SQL文を書くことで、パフォーマンスの最適化や細かいデータ操作が可能になります。
プロジェクトの要件に応じて、適切なデータベースアクセス方法を選択することが重要です。


