2

同じクラスの Active Record オブジェクトの配列があります。そのオブジェクトには定義済みの関係があります。「親」オブジェクトが初期化された後、関連するオブジェクトを「一括」で読み取る方法はありますか?

例 AR クラスPostUserComment * Post *をクラスUserへのリレーション所有者(BELONGS_TO) と、クラスComments へのリレーションコメント(HAS_MANY) を定義しました。

クラスPostのオブジェクトの配列$postsがあります。別の理由で、$postsを最初から初期化することはできません

'with' => array('owner', 'comments')

私がこれを行う場合:

foreach ($posts as $post) {
   var_dump($post->owner);
   var_dump($post->comments);
}

$postごとに、所有者を取得するためのクエリとコメントを取得するためのクエリを作成する必要があります。これにより、多くのクエリが発生し、スクリプトの実行が遅くなる可能性があります。より良いアプローチは、1 つのタイプのすべての関連オブジェクトを 1 つのステップで読み取ることです。

オブジェクトの配列の特定の関係に関連するすべてのオブジェクトを取得するために、このようなものは存在しますか?:

Post::readRelatedObject($posts, 'owner'); 
Post::readRelatedObject($posts, 'comments');

いくつかの理由から、このアプローチが必要です。

  1. リレーションを初期化する必要があるかどうかを事前に判断できないことがあります。
  2. 結合が遅くなる可能性があるため、「親」の後に関連するオブジェクトを読み取る方がはるかに高速になる可能性があります。
  3. 「親」オブジェクトが関連オブジェクトと同じキャッシュ時間を持てない場合があるため、キャッシュが影響を受ける可能性があるため、親オブジェクトがキャッシュから抽出された後に、関連オブジェクトをグループ化/一括で読み取ることが役立つ場合があります。例: $postはキャッシュされましたが、投稿と一緒に最後の 3 つのコメントをキャッシュできません。

yii にはこのようなものが含まれていますか? または役立つプラグインですか?

ありがとうございました

4

3 に答える 3

2

このような大規模な結果セットを最適化しようとしている場合は、ほとんどの場合、独自の結果セットを作成することをお勧めします。Yiiの開発者は、このような複雑な状況(ロード順序が大きく異なる)ではactiverecordを使用しないことを推奨しています。

それでも

まず、CDBCriteria取得したすべての投稿のIDに基づいて独自の投稿を作成することをお勧めします。モデル内でこれを行うPostsと、関係に対して定義された基準ともうまく結び付けられます(明らかに完全ではありません)。

static public function loadComments(array $ids)
{
    $crit = Comment::model()->dbCriteria;
    $crit->addInCondition('post_id', .....

    .....
    return Comment::model()->findAll($crit);
}

これにより、そのIDのセットに対するすべてのコメントが返されます。追加の処理を行って、それらが属する投稿IDでインデックスを作成することもできます。

しかし、本当に

あなたのコメントでは、この100件の投稿とそれぞれ200件のコメントは、2000(実際には20000)の読み込みを意味する可能性があると言います。ただし、1つのページにその数の投稿とコメントを読み込んでいる場合は、間違った場所で最適化しています。

私の意見では、DBクエリのサイズについて心配する前に実装することがいくつかあります。

  1. 必要になるまでコメントを読み込まないでください。ボタンをクリックするか、投稿のタイトルまでスクロールするか、ページが完了するまでページを下に移動します。このように、サーバーは一度に1つの投稿のコメントのみを検索し、ユーザーは投稿番号99のコメントを見たくない場合もあります。

  2. 非常に小さな投稿でない限り、ページごとに100件の投稿を読み込まないでください(この場合、心配する必要はありません)。再びプログレッシブスクロールすると、さらにはページネーションが役立ちます

  3. 結果をフィルタリングして、関連するものだけを表示します。ユーザーが見たい投稿は100件ではない可能性が非常に高く、コメントが200件ある場合、10人以上を読むユーザーは何人ですか。

これらを1つでも実装すれば、結果セットのサイズの問題は簡単になくなると思います。

でも

本当に20000行について心配する必要がある場合は、ActiveRecordのインスタンス化を最初に行う必要があります。20000行は通常のセットアップでは心配する必要はありませんが、20000のアクティブなレコードオブジェクトは、より高いスペックのシステムでも確かにそうです。非常に大規模なデータセットや複雑なデータセットを扱う場合は、DAOを使用する必要があります。

于 2013-02-28T15:27:36.590 に答える
0

これを行うことができる拡張機能については知りません。おそらく、このタスクを解決するために、データに関するすべてを知っている yii を 1 つ作成することができます。

テーブル内の にリンクする があるcommentとします。post_ididpost

投稿の関連コメントを読み込むためのオプションがいくつかあります。

オプション 1 : ID を使用して、必要なコメントをクエリします。一部の DBMS では SQL クエリの長​​さが制限されているため、IN 句に多くの ID を指定しないように注意する必要があります。おそらく、これは複数のクエリに分割する必要があります。

  1. 与えられたを反復し$posts、投稿idをリストに保存します。
  2. のような SQL クエリを実行しますSELECT * FROM comments WHERE post_id IN ([the IDs from the list])
  3. 結果を にマージします$posts

オプション 2 : IN 句の制限を修正するには、代わりに JOIN を使用します。

  1. のような SQL クエリを実行しますSELECT * FROM comments JOIN [the SELECT query for the posts]

オプション 3 (私の好み): ユース ケースによっては、コメントと作成者を含むすべての投稿をリロードするのが最もクリーンな場合があります (モデルでを定義withすることにより)。criteriaposts

  1. 条件を追加しますwith:if ($loadDetails) { criteria->'with' => array('owner', 'comments'); }
于 2013-02-24T11:32:20.617 に答える
0

あなたの主な関心事が遅延読み込みを避けることであり、所有者とコメントの関連レコードとともにすべての投稿を取得したい場合。

これはあなたにとって役立つかもしれません。

$criteria = new CDbCriteria();
$criteria->with = array('comments','owner');
$result = $Post->together()->findAll($criteria);

参照: http://www.yiiframework.com/doc/api/1.1/CActiveRecord#together-detail http://www.yiiframework.com/doc/api/1.1/CDbCriteria#with-detail

これがあなたの質問に答えることを願っています。

于 2013-02-27T04:02:18.313 に答える