ORM-悪、またはどのようにしてSymfonyでPropelをキャッシュしたか

1つのプロジェクト(ソーシャルネットワーク)に取り組んで、私はmemcacheデータモデルで「友達を作る」というタスクに直面しました。 タイトルからすでに理解しているように、プロジェクトはsymfonyフレームワークで記述され、PropelはORMとして使用されます。



なぜビューキャッシュを使用できるのか、モデルをキャッシュするのはなぜですか?

実践が示しているように(最初は使用されていたのはビューキャッシュでした)、これは不適切であることがわかりました。 ユーザーがデータを変更するたびに、いくつかのキャッシュされたブロックのキャッシュを一度にフラッシュする必要がありました。 プロジェクトの開発に伴うこれらのブロックの数は増え続けており、ロジックは複雑です。 脳を和らげ、間違いを避けるために、モデルをキャッシュすることにしました。



判明したように、Propelはキャッシュを目的としておらず、キャッシュビューが無効になっていると、非常に多くのリクエストを生成します。

私の記録は250です!!! なぜあなたは尋ねますか? Propelは興味深い方法でオブジェクト間の接続を実装するためです。 単一のポイントからオブジェクトを取得する代わりに(たとえば、retriveByPkメソッドを使用して)、データベースに要求を行います!!! これは、ユーザーのオブジェクト、写真、ブログエントリがある場合、各オブジェクトからデータベースへのリクエストを取得することを意味します。 たとえば、20枚の写真のサンプルがあります-データベースへの20のリクエストを取得して、写真の著者名を見つけます。 写真に別のアルバムがある場合 それは40です。そして、これが写真、ブログエントリ、その他多くのメインページである場合は!? すべて250



Propel'eで興味深いのはこれについて警告します:)

以下に例を示します。

public function getsfGuardUser(PropelPDO $con = null )

{

if ($ this ->asfGuardUser === null && ($ this ->user_id !== null )) {

$c = new Criteria(sfGuardUserPeer::DATABASE_NAME);

$c->add(sfGuardUserPeer::ID, $ this ->user_id);

$ this ->asfGuardUser = sfGuardUserPeer::doSelectOne($c, $con);

/* The following can be used additionally to

guarantee the related object contains a reference

to this object. This level of coupling may, however, be

undesirable since it could result in an only partially populated collection

in the referenced object.

$this->asfGuardUser->addPhotos($this);

*/

}

return $ this ->asfGuardUser;

}



* This source code was highlighted with Source Code Highlighter .






そして次のことができます:

public function getsfGuardUser(PropelPDO $con = null )

{

return sfGuardUserPeer::retrieveByPK($ this ->getUserId(), $con);

}



* This source code was highlighted with Source Code Highlighter .








この単純な再定義では、「余分な」リクエストを取り除くことができます

ただし、多くの接続がある場合は、コードを詳しく調べる必要があります。



次に、キャッシュに直接渡します。 retrieveByPKメソッドを呼び出した後、オブジェクトが存在する場合はキャッシュから返され、存在しない場合はデータベースから取得されてキャッシュに保存されるようにしました。 最も興味深いことに、propelにはロードされたオブジェクトのプールがあります。 このプールは単なる一時的なストレージです。

ユーザーモデル用に生成されたメソッドの例を次に示します。

public static function addInstanceToPool(sfGuardUser $obj, $key = null );

public static function removeInstanceFromPool($ value );

public static function getInstanceFromPool($key);

public static function clearInstancePool();



* This source code was highlighted with Source Code Highlighter .








また、プールに分類されるオブジェクトがmemcacheに同時にキャッシュされるようにこれらのメソッドを再定義すると、モデルオブジェクトをキャッシュするタスクが解決されます。 確かに、これはエレガントなソリューションではありませんが、Propelモデルではオブジェクトは互いに分離されています。 そして、もし何かができれば、それより低いレベル、つまりフレームワークのレベルで。 これは、symfonyを更新する際にそのような変更を考慮する必要があることを意味し、非常に不便です。



Propelは大規模で複雑なWebプロジェクトを構築するために使用すべきではありません。



UPD

結合は適切ではありません、なぜなら 多くの結合を使用することはお勧めしません。これは、要求がより複雑になるため、データベースへの追加の負荷になります。 重い負荷では、これは重要です。 しかし、単純な要求ですべてを実行し、主キーのキーをプルすると、すべてが適切に配置されます。 例。 20枚の写真を選択し、アルバム、著者、著者アバター、アルバムアバターがあります。 結合では、5つのテーブルの接続を持つクエリがあります!!! そして、ページあたり5つのそのようなページがある場合!? そして、私の場合、それだけです!



UPD2

記事を注意深く読んでください))



UPD3

物語の続き

SymfonyでmemcacheとPropelを友達にした方法



All Articles