7

Ho una grande query (nel mio generatore di query) e molti join di sinistra. Quindi ottengo articoli con i loro commenti e tag e così via. Diciamo che ho il seguente DQL:Doctrine2: Limitazione con join/impaginazione sinistra - Best Practice

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

Ora diciamo che il mio database ha più di 100 blogposts ma voglio solo il primo 10, ma con tutti i commenti di chi 10 e tutte le loro etichette, se esistono . Se uso setMaxResults limita le righe. Quindi potrei ottenere i primi due post, ma l'ultimo di questi manca alcuni dei commenti o dei tag. Quindi il seguito non funziona.

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

Utilizzando la malapena documentato Pagination Soluzione fornito con doctrine2.2 in realtà non funziona neanche per me dal momento che è così lento, ho potuto così caricare tutti i dati.

Ho provato le soluzioni nello Stackoverflow Article, ma anche quell'articolo manca ancora una best practice e la soluzione presentata è mortalmente lenta.

Non esiste una procedura ottimale su come eseguire questa operazione? Nessuno usa Doctrine2.2 in modalità Produzione?

+1

Si prega di aggiungere il codice che avete alla vostra domanda, magari anche con risultati di esempio per mostrare ciò che si desidera, e ciò che si sta ottenendo. –

risposta

10

Ottenere risultati corretti con una query come questa è problematico. Esiste un tutorial sul sito Web di Doctrine che spiega questo problema.

Pagination

Il tutorial è più circa l'impaginazione piuttosto che ottenere i primi 5 risultati, ma l'idea generale è che avete bisogno di fare un "SELECT a.id DISTINTO DA articoli a ... limite del 5" al posto di un normale SELECT. È un po 'più complicato di questo, ma gli ultimi 2 punti in questo tutorial dovrebbero metterti sulla giusta strada.

Aggiornamento:

Il problema qui non è la dottrina, o di qualsiasi altro ORM. Il problema sta nel fatto che il database è in grado di restituire i risultati che stai richiedendo. Questo è il modo in cui i join funzionano.

Se si esegue una SPIEGA sulla query, si otterrà una risposta più approfondita di ciò che sta accadendo. Sarebbe una buona idea aggiungere i risultati di questo alla tua domanda iniziale.

Basandosi su quanto discusso nell'articolo di Paginazione, sembrerebbe che siano necessarie almeno 2 query per ottenere i risultati desiderati. L'aggiunta di DISTINCT a una query ha il potenziale per rallentare drasticamente la query, ma è davvero necessaria solo se ci si aggiunge a essa. Potresti scrivere un'altra query che recupera solo i primi 10 post ordinati per data di creazione, senza i join. Una volta ottenuti gli ID di questi 10 post, esegui un'altra query con i tuoi join e un WHERE blogpost.id IN (...) ORDER BY blogpost.created. Questo metodo dovrebbe essere molto più efficiente.

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

Poiché tutto ciò che interessa nella prima query sono gli ID, è possibile impostare Doctrine da usare scalare idratazione.

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

Si potrebbe anche probabilmente farlo in una query utilizzando una sottoquery correlata. Il mito che le subquery sono sempre cattive NON è vero. A volte sono più veloci dei join. Avrai bisogno di sperimentare per scoprire quale sia la soluzione migliore per te.

2

Modifica alla luce della domanda chiarito:

si può fare quello che vuoi in MySQL nativo utilizzando una subquery nella clausola FROM in quanto tale:

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 

Per quanto ne so, DQL non supporta sottoquery come questo, quindi puoi usare la classe NativeQuery.

+0

No, non voglio il più recente M del mio N. Voglio il più recente N con tutti i loro M, X e Y. –

+0

Non sono un grande fan dell'utilizzo di un DABL/ORM Framework e quindi utilizzo ancora nativo Interrogazioni. Non ha molto senso per me. –

+1

Quindi sembra che sarà necessario effettuare due query. Sono d'accordo che ci dovrebbe essere un modo migliore per limitare e visualizzare i risultati di join. –