======== はじめに ======== ``Doctrine_Cache``は直感的で使いやすいキャッシュのソリューションを提供します。: - 複数のキャッシュのバックエンド(Memcached、APCとSqliteを服務) - 微調整できる高度なオプション。``Doctrine_Cache``はパフォーマンスの微調整用のたくさんのオプションを持つ。 すべてのキャッシュドライバは次のようにインスタンス化されます: // bootstrap.php // ... $options = array(); :code:`cacheDriver = new Doctrine_Cache_Memcache(`\ options); **NOTE** それぞれのドライバは配列``$options``用の独自の値を持ちます。 ======== ドライバ ======== ---------------- Memcache ---------------- Memcacheドライバはキャッシュレコードをmemcachedサーバーに保存します。Memcachedはハイパフォーマンスで、 分散型のメモリオブジェクトキャッシュシステムです。これをバックエンドに使うには、memcachedデーモンとPECLのmemcacheエクステンションが必要です。 Memcacheキャッシュドライバは次のコードでインスタンス化できます: // bootstrap.php // ... $servers = array( 'host' => 'localhost', 'port' => 11211, 'persistent' => true ); $cacheDriver = new Doctrine\_Cache\_Memcache(array( 'servers' => $servers, 'compression' => false ) ); **NOTE** Memcacheは複数のサーバーを許可します。 Memcacheドライバで利用できるオプション: \|\|~ オプション \|\|~ データ型 \|\|~ デフォルト値 \|\|~ 説明 \|\| \|\| ``servers`` \|\| ``array`` \|\| ``array(array('host' => 'localhost','port' => 11211, 'persistent' => true))`` \|\| memcachedサーバーの配列; それぞれのmemcachedサーバーは連想配列で記述される: ``'host' => (string)`` : memcachedサーバーの名前、``'port' => (int)`` : memcachedサーバーのポート、``'persistent' => (bool)`` : memcachedサーバーへの永続接続を使うかどうか \|\| \|\| ``compression`` \|\| ``boolean`` \|\| ``false`` \|\| 即座に圧縮したい場合は``true`` \|\| ------ APC ------ Alternative PHP Cache (APC)はフリーでPHPのためのオープンなオプコードキャッシュです。これはPHPの中間コードのキャッシュと最適化のための頑強なフレームワークとも認識されています。DoctrineのAPCキャッシュドライバはキャッシュレコードを共用メモリに保存します。 次のコードでAPCキャッシュドライバをインスタンス化できます: // bootstrap.php // ... $cacheDriver = new Doctrine\_Cache\_Apc(); ---- Db ---- Dbキャッシュバックエンドはキャッシュレコードを任意のデータベースに保存します。通常は処理が速いフラットファイルベースのデータベースが使われます(sqliteなど)。 次のコードでデータベースキャッシュをインスタンス化できます: // bootstrap.php // ... $cacheConn = Doctrine\_Manager::connection(new PDO('sqlite::memory:')); $cacheDriver = new Doctrine\_Cache\_Db(array('connection' => $cacheConn)); ================================ クエリキャッシュと結果キャッシュ ================================ -------- はじめに -------- DoctrineはDQLクエリの最終結果(データ)と同様にDQLの解析処理の結果をキャッシュする方法を提供します。これら2つのキャッシュメカニズムはパフォーマンスを大いに向上させます。DQLクエリ実行の標準ワークフローを考えてみましょう: 新しいDQLクエリを初期化する =========================== DQLクエリを解析する =================== データベース固有のSQLクエリをビルドする ======================================= SQLクエリを実行する =================== 結果セットをビルドする ====================== 結果セットを返す ================ これらのフェーズはとても時間がかかります。とりわけクエリをデータベースサーバーに送信するフェーズ4は時間がかかります。Doctrineクエリキャッシュが実行されているとき次のフェーズが行われます: 新しいDQLクエリを初期化する =========================== SQLクエリを実行する(キャッシュから取得) ======================================= 結果セットをビルドする ====================== 結果セットを返す ================ DQLクエリが有効なキャッシュエントリーを持つ場合キャッシュされたSQLクエリが使われ、さもなければフェーズ2-3が実行されこれらのステップの結果がキャッシュに保存されます。最新のクエリ結果を常に得られるのでクエリキャッシュには不都合なことはありません。 **NOTE** 本番環境では常にクエリキャッシュを使うべきです。すなわち開発期間も簡単に使えます。DQLクエリを変更して実行するときキャッシュが修正されたことをDoctrineが最初に確認して新しいキャッシュエントリを作ります。そのためキャッシュを取り消す必要はありません。 クエリキャッシュの効率性がプリペアードステートメントの使い方(ともかくDoctrineはデフォルトで使用)に依存するのは無意味です。動的なクエリの部分を直接埋め込む代わりに常にプレースホルダーを使うべきです。 結果キャッシュを使えば状況がよくなります。クエリ処理は次のようになります(有効なキャッシュエントリが見つかることが前提): 新しいDQLクエリを初期化する =========================== 結果セットを返す ================ ご覧の通り、結果キャッシュは以前示されたクエリキャッシュを暗に伝えます。クエリによって返されるデータが最新である必要がなければ結果キャッシュを使うことを常に考えるべきです。 ---------------- クエリキャッシュ ---------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ クエリキャッシュを使用する ^^^^^^^^^^^^^^^^^^^^^^^^^^ ``Doctrine\_Core::ATTR\_QUERY_CACHE``属性を使用することで接続もしくは管理レベルのクエリキャッシュドライバを設定できます。接続レベルのキャッシュドライバを設定することはこの接続で実行されるすべてのドライバは特定のキャッシュドライバを使用するのに大してマネージャーレベルのキャッシュドライバを設定することは(接続レベルでオーバーライドされない限り)すべての接続が任意のキャッシュドライバを使用することを意味します。 **マネージャーレベルのクエリキャッシュドライバを設定する:** // bootstrap.php // ... $manager->setAttribute(Doctrine\_Core::ATTR\_QUERY\_CACHE, $cacheDriver); **NOTE** ``$cacheDriver``の値はこの章の前のセクションでインスタンス化されたドライバになります。 **接続レベルのキャッシュドライバを設定する:** // bootstrap.php // ... $conn->setAttribute(Doctrine\_Core::ATTR\_QUERY\_CACHE, $cacheDriver); ^^^^^^^^^^ 微調整する ^^^^^^^^^^ 以前の章でグローバルキャッシュの属性を使いました。これらの属性はクエリレベルでオーバーライドできます。``useQueryCache()``を呼び出すことでキャッシュドライバをオーバーライドしてこれにDoctrineの有効なキャッシュドライバを渡すことができます。これはクエリキャッシュにはほとんど意味ありませんが可能です: $q = Doctrine\_Query::create() ->useQueryCache(new Doctrine\_Cache\_Apc()); -------------- 結果キャッシュ -------------- ^^^^^^^^^^^^^^^^^^^^^^^^ 結果キャッシュを使用する ^^^^^^^^^^^^^^^^^^^^^^^^ ``Doctrine\_Core::ATTR\_RESULT_CACHE``を使用することで接続もしくはマネージャーレベルの結果キャッシュドライバを設定できます。接続レベルのキャッシュドライバはこの接続で実行されるすべてのクエリが指定されたキャッシュドライバを使用するのに対してマネージャーレベルのキャッシュドライバは(接続レベルでオーバーライドされない限り)すべての接続が任意のキャッシュドライバを使用することを意味します。 **マネージャーレベルのキャッシュドライバを設定する:** // bootstrap.php // ... $manager->setAttribute(Doctrine\_Core::ATTR\_RESULT\_CACHE, $cacheDriver); **接続レベルのキャッシュドライバを設定する:** // bootstrap.php // ... $conn->setAttribute(Doctrine\_Core::ATTR\_RESULT\_CACHE, $cacheDriver); 通常キャッシュエントリは同じ時間に対してのみ有効です。``Doctrine\_Core::ATTR\_RESULT\_CACHE_LIFESPAN``を使用することでキャッシュエントリの有効な期間のためのグローバルな値を設定できます。 **寿命を1時間に設定する(60秒 \* 60 = 1時間 = 3600秒):** // bootstrap.php // ... $manager->setAttribute(Doctrine\_Core::ATTR\_RESULT\_CACHE\_LIFESPAN, 3600); キャッシュドライバを設定したので``userResultCache()``メソッドを呼び出すことでDQLクエリを使うことができます: **blog投稿のタイトルとコメントの数を取得する:** $q = Doctrine\_Query::create(); ->select('b.title, COUNT(c.id) count') ->from('BlogPost b') ->leftJoin('b.Comments c') ->limit(10) ->useResultCache(true); $blogPosts = $q->execute(); ^^^^^^^^^^ 微調整する ^^^^^^^^^^ 以前の章でグローバルキャッシュ属性を使いました。これらの属性はクエリレベルでオーバーライドできます。``useCache()``を呼び出してキャッシュドライバをオーバーライドしこれらにDoctrineのキャッシュドライバのインスタンスを渡すことができます。 $q = Doctrine\_Query::create() ->useResultCache(new Doctrine\_Cache\_Apc()); ``setResultCacheLifeSpan()``を呼び出すことでもlifespan属性をオーバーライドできます: $q = Doctrine\_Query::create() ->setResultCacheLifeSpan(60 \* 30); ====== まとめ ====== 開発と本番環境の両方でDoctrineのキャッシュ機能を使うことは大いにお勧めします。使うことで不都合な影響はなくアプリケーションのパフォーマンスの改善に役立ちます。 キャッシュ機能はこの本で検討される最後から2番目の機能です。この後のDoctrineで使われている[doc technology テクノロジー]、[doc coding-standards コーディング規約]と[doc unit-testing ユニットテスト]の章はまとめです。最後の機能である[doc migrations :name]を検討するために移動しましょう。