7

大きなクエリ (クエリ ビルダー内) と多くの左結合があります。そのため、コメントやタグなどを含む記事を取得します。次のdqlがあるとしましょう:

$dql = 'SELECT blogpost, comment, tags 
FROM BlogPost blogpost 
LEFT JOIN blogpost.comments comments
LEFT JOIN blogpost.tags tags';

ここで、データベースに 100 件を超えるブログ投稿があり、最初の 10 件のみが必要であるとしますが、それらの 10 件のすべてのコメントと、存在する場合はすべてのタグが必要です。setMaxResults を使用すると、行が制限されます。したがって、最初の 2 つの投稿を取得することができますが、最後の投稿にはコメントまたはタグの一部がありません。したがって、フォローは機能しません。

$result = $em->createQuery($dql)->setMaxResults(15)->getResult();

doctrine2.2 に同梱されているほとんど文書化されていないPagination Solution を使用しても、非常に遅いため、実際には機能しません。すべてのデータをロードすることもできます。

Stackoverflow Articleのソリューションを試しましたが、その記事にもまだベスト プラクティスがなく、提示されたソリューションは非常に遅いです。

これを行う方法に関するベストプラクティスはありませんか? プロダクションモードで Doctrine2.2 を使っている人はいませんか?

4

2 に答える 2

11

このようなクエリで適切な結果を得るには問題があります。Doctrine の Web サイトには、この問題を説明するチュートリアルがあります。

ページネーション

このチュートリアルは、上位 5 つの結果を得ることよりもページネーションに関するものですが、全体的な考え方は、通常の SELECT の代わりに「SELECT DISTINCT a.id FROM article a ... LIMIT 5」を実行する必要があるということです。これより少し複雑ですが、このチュートリアルの最後の 2 つのポイントを理解すれば、正しい軌道に乗ることができます。

アップデート:

ここでの問題は、Doctrine やその他の ORM ではありません。問題は、データベースが求めている結果を返すことができることにあります。これが結合の仕組みです。

クエリで EXPLAIN を実行すると、何が起こっているかについてより詳細な回答が得られます。その結果を最初の質問に追加することをお勧めします。

ページネーションの記事で説明されている内容に基づいて構築すると、目的の結果を得るには少なくとも 2 つのクエリが必要になるようです。クエリに DISTINCT を追加すると、クエリが大幅に遅くなる可能性がありますが、実際に必要になるのは結合がある場合だけです。結合なしで、作成日順に並べ替えられた最初の 10 件の投稿を取得するだけの別のクエリを作成できます。これらの 10 件の投稿の ID を取得したら、結合を使用して別のクエリを実行し、WHERE blogpost.id IN (...) ORDER BY blogpost.created. この方法ははるかに効率的です。

SELECT 
    bp 
FROM 
    Blogpost bp 
ORDER BY 
    bp.created DESC
LIMIT 10

最初のクエリで気にするのは ID だけなので、Doctrine で Scalar Hydration を使用するように設定できます。

SELECT 
    bg 
FROM 
    Blogpost bp 
LEFT JOIN 
    bp.comments c 
LEFT JOIN 
    bp.tags t 
WHERE 
    bp.id IN (...) 
ORDER BY 
    bp.created DESC

相関サブクエリを使用して、1 つのクエリで実行することもできます。サブクエリは常に悪いという神話は真実ではありません。結合よりも高速な場合があります。最善の解決策を見つけるには、実験を行う必要があります。

于 2012-06-08T00:42:46.130 に答える
2

明確な質問に照らして編集します。

FROM 句のサブクエリを次のように使用して、ネイティブ MySQL で必要なことを行うことができます。

SELECT * FROM 
 (SELECT * FROM articles ORDER BY date LIMIT 5) AS limited_articles, 
 comments, 
 tags 
WHERE
 limited_articles.article_id=comments.article_id
 limited_articles.article_id=tags.article_id

私の知る限り、DQL はこのようなサブクエリをサポートしていないため、NativeQuery クラスを使用できます。

于 2012-06-07T23:42:26.447 に答える