Pergunta

eu tenho uma grande consulta (no meu construtor de consultas) e muitas junções à esquerda.Então recebo artigos com seus comentários e tags e assim por diante.Digamos que eu tenha o seguinte dql:

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

Agora digamos que meu banco de dados tenha mais de 100 posts de blog, mas eu quero apenas os 10 primeiros, mas com todos os comentários desses 10 e todas as suas tags, se existirem.Se eu usar setMaxResults, isso limitará as linhas.Talvez eu receba as duas primeiras postagens, mas a última delas está faltando alguns comentários ou tags.Portanto, o seguinte não funciona.

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

Usando o pouco documentado Paginação A solução que vem com o doutrina2.2 também não funciona para mim, pois é tão lenta que eu também poderia carregar todos os dados.

Eu tentei as soluções no Artigo Stackoverflow, mas mesmo esse artigo ainda carece de uma melhor prática e a solução apresentada é mortalmente lenta.

Não existe uma prática recomendada sobre como fazer isso?Ninguém está usando o Doctrine2.2 no modo de produção?

Foi útil?

Solução

Obter os resultados adequados com uma consulta como esta é problemático.Há um tutorial no site do Doctrine explicando esse problema.

Paginação

O tutorial é mais sobre paginação do que obter os 5 principais resultados, mas a ideia geral é que você precisa fazer um "SELECT DISTINCT a.id FROM articles a ...LIMIT 5" em vez de um SELECT normal.É um pouco mais complicado do que isso, mas os dois últimos pontos desse tutorial devem colocá-lo no caminho certo.

Atualizar:

O problema aqui não é o Doctrine ou qualquer outro ORM.O problema está diretamente no fato de o banco de dados ser capaz de retornar os resultados que você está solicitando.É assim que as junções funcionam.

Se você fizer um EXPLAIN na consulta, você terá uma resposta mais aprofundada sobre o que está acontecendo.Seria uma boa ideia adicionar os resultados disso à sua pergunta inicial.

Com base no que é discutido no artigo Paginação, parece que você precisa de pelo menos duas consultas para obter os resultados desejados.Adicionar DISTINCT a uma consulta tem o potencial de desacelerar drasticamente sua consulta, mas só é realmente necessário se você tiver junções nela.Você poderia escrever outra consulta que recuperasse apenas as 10 primeiras postagens ordenadas por data de criação, sem as junções.Depois de ter os IDs dessas 10 postagens, faça outra consulta com suas junções e uma WHERE blogpost.id IN (...) ORDER BY blogpost.created.Este método deve ser muito mais eficiente.

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

Como tudo o que importa na primeira consulta são os IDs, você pode configurar o Doctrine para usar a hidratação escalar.

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

Você provavelmente também poderia fazer isso em uma consulta usando uma subconsulta correlacionada.O mito de que as subconsultas são sempre ruins NÃO é verdade.Às vezes, eles são mais rápidos que junções.Você precisará experimentar para descobrir qual é a melhor solução para você.

Outras dicas

Editar à luz da questão esclarecida:

Você pode fazer o que quiser no MySQL nativo usando uma subconsulta na cláusula FROM como tal:

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

Até onde eu sei, o DQL não suporta subconsultas como essa, então você pode usar a classe NativeQuery.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top