PHPでは、 pdostatement :: fetchObjectは、データベースからデータを取得するために一般的に使用される方法です。通常、この方法を使用して、rowまたはバッチごとにデータの行を取得します。ただし、場合によっては、クエリを複数回実行すると重複クエリが発生し、パフォーマンスの問題が発生する場合があります。これを回避するために、さまざまな方法でクエリを最適化して、クエリされたデータが繰り返されないことを確認できます。
この記事では、例を使用して、 pdostatement :: fetchobjectを使用してデータを複数回取得し、一般的に使用される最適化戦略を提供するときに、重複クエリを避ける方法を説明します。
まず、 pdostatement :: fetchObjectメソッドがどのように機能するかを理解することが非常に重要です。このメソッドは、現在の結果行のオブジェクト表現を返し、呼び出されるたびにポインターを次の行に移動します。典型的な使用法は次のとおりです。
<?php
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'username', 'password');
$stmt = $pdo->prepare("SELECT id, name FROM users");
$stmt->execute();
while ($user = $stmt->fetchObject()) {
echo $user->id . ' - ' . $user->name . "<br>";
}
?>
上記のコードはクエリを実行し、データ行ごとにデータを出力します。 FetchObject()が呼び出されるたびに、データベースにリクエストが開始されます。
複数の場所でFetchObjectを呼び出す可能性がある、より複雑なクエリロジックがあると仮定します。これにより、クエリが重複する可能性があります。たとえば、一部のユーザーデータは複数のページまたは操作で取得する必要があります。また、毎回データベースが再作成されている場合、パフォーマンスが影響を受けます。
最適化する1つの方法は、クエリの重複を避けるためにキャッシュを使用することです。初めてデータを照会すると、結果をメモリにキャッシュできます(たとえば、 APCUやPHPでmemcachedなどのキャッシュメカニズムを介して)。その後のリクエストでは、データベースを再度照会せずにキャッシュから直接データを取得できます。
たとえば、 APCUキャッシュを使用した簡単な実装:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'username', 'password');
$stmt = $pdo->prepare("SELECT id, name FROM users");
$stmt->execute();
while ($user = $stmt->fetchObject()) {
// 使用 APCu キャッシュ
$cacheKey = 'user_' . $user->id;
if (!apcu_exists($cacheKey)) {
apcu_store($cacheKey, $user);
}
$cachedUser = apcu_fetch($cacheKey);
echo $cachedUser->id . ' - ' . $cachedUser->name . "<br>";
}
?>
この例では、 APCUを使用して各ユーザーオブジェクトをキャッシュします。データがキャッシュされている場合は、データベースから再クエリする代わりに、キャッシュされたデータを直接使用します。
クエリが大量のデータを返す場合、別の最適化戦略は、ページネーションクエリを使用することです。クエリの結果をバッチにロードすることにより、一度にデータをロードしすぎないようにして、複数のクエリになります。
ページネーションクエリの例は次のとおりです。
<?php
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'username', 'password');
$limit = 10; // 各クエリ10データ
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$offset = ($page - 1) * $limit;
$stmt = $pdo->prepare("SELECT id, name FROM users LIMIT :limit OFFSET :offset");
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
while ($user = $stmt->fetchObject()) {
echo $user->id . ' - ' . $user->name . "<br>";
}
?>
この例では、制限とオフセットがページネーションクエリに使用され、必要なデータの一部のみが一度にすべてのデータロードではなく、一度にロードされるようにします。
同じスクリプトで同じクエリ結果が複数回必要な場合は、 FetchObjectを複数回呼び出す代わりに、クエリ結果を変数にキャッシュすることを検討してください。例えば:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'username', 'password');
$stmt = $pdo->prepare("SELECT id, name FROM users");
$stmt->execute();
$users = [];
while ($user = $stmt->fetchObject()) {
$users[] = $user;
}
// ロードされたユーザーデータのその後の使用,二度とクエリなしで
foreach ($users as $user) {
echo $user->id . ' - ' . $user->name . "<br>";
}
?>
ここでは、クエリ結果を$ユーザーアレイに保存して、後続のコードでデータベースの繰り返しクエリを繰り返さないようにします。
キャッシュとページングに加えて、以下は一般的に使用される最適化戦略です。
[select * :データの転送を減らすために必要なフィールドのみを選択してください。
バッチクエリ:1つずつクエリするのではなく、複数のレコードを一度に照会してみてください。
インデックスの使用:データベーステーブルの関連するフィールドに、クエリ効率を改善するための適切なインデックスがあることを確認してください。