DAO orientato a CRUD multipli, ma richiede una sorta di join di dati di grandi dimensioni

2

Al lavoro mi è stato assegnato un compito per indagare sulla grave lentezza di un'applicazione che non conosco. Richieste semplici richiedevano diversi minuti per risolverlo.

Ecco com'era prima (semplificando):

  • Esiste un metodo di facciata per ottenere un sottoinsieme di informazioni sugli ordini, con i clienti

  • Esiste un CustomerDAO, costruito attorno ai principi CRUD

  • Esiste un OrderDAO, costruito attorno ai principi CRUD

  • Il metodo della facciata chiama OrderDAO.find(...) , quindi per ogni ordine chiama CustomerDAO.find(order.getCustomerId())

I'm oversimplifying here, I'll pass most of the details. This isn't even orders and customers I had to deal with, and there are other DAOs called in the process. You have to trust me when I say that the matter was much more complicated than this, the amount of redundant calls was absurd.

There was a case where a findBy(...) method returned all the parents and each parent had a list of children, but for some reason within the DAO logic it would call find(parentId) for the child, so the parent's model was present 1 + the number of children times in the returned model, totaling 1 + the number of children x 2 queries per parent. I don't know why the children have a copy of their parent, but it's done that way; enhancing that would be out of the scope of my activities.

Ancora più importante, la facciata restituisce solo un sottoinsieme delle informazioni recuperate presenti nel modello. Alcuni dati con una propria query all'interno della logica DAO sono stati scartati.

All'inizio ho cercato di preservare l'architettura corrente aggiungendo una cache e ottimizzando alcune chiamate ridondanti, ma i risultati erano ancora mediocri.

Ho risolto il problema della lentezza eseguendo una query di database che unisce le tabelle e creando i modelli di sottoinsieme invece di creare i modelli completi, riducendo il tempo di elaborazione da alcuni minuti a un paio di secondi. La firma della facciata rimane invariata.

Tuttavia, ritengo che questa soluzione sia completamente fuori luogo rispetto al resto dell'applicazione. La logica che si verifica all'interno di questo nuovo metodo è molto specifica. Inoltre, non restituisco più clienti o ordini, quindi questa nuova strategia non sembra appartenere ai DAO.

Quale sarebbe un approccio corretto per affrontare un problema di prestazioni che è facilmente risolvibile bypassando i DAO orientati a CRUD? In genere se ho più DAO orientati al CRUD ma ho bisogno di un qualche tipo di dati di grandi dimensioni, cosa dovrei fare?

    
posta Hay 31.12.2016 - 03:48
fonte

1 risposta

2

Senza conoscere il codice reale posso solo indovinare ciò che manca in questo caso, ma per la mia esperienza, molti problemi di prestazioni nei DAO possono essere risolti aggiungendo alcune semplici estensioni ai metodi CRUD standard.

Ad esempio,

  • i metodi Read o SELECT possono fornire un parametro stringa wherecondition e restituire più record contemporaneamente. Questo approccio consentirà al chiamante di utilizzare complessi join, subquery o operazioni UNION, in modo trasparente, in combinazione con le operazioni CRUD standard. (Lo svantaggio è che introduce la possibilità di collocare SQL specifico del fornitore al di fuori del livello DAO). A volte è anche utile fornire un parametro con un elenco di ID / chiavi nel metodo Read , e quest'ultimo usa il comando SQL ".. WHERE id IN (...)" per caricare quei record in uno andata e ritorno. Ciò consente di lavorare con interi set di record senza incorrere nel problema con SQL specifico del fornitore.

  • introducendo la possibilità di "oggetti / record caricati imparziali": crea metodi nel livello DAO in cui è possibile specificare di non caricare immediatamente gli oggetti completi. Fornire un meccanismo per consentire il caricamento delle parti mancanti di oggetti / record in seguito, ma solo se sono realmente necessari ("caricamento lento"). Questo può diventare molto efficiente quando le parti lazy load richiedono query aggiuntive o subquery complesse.

Quindi penso che tu abbia un'idea generale: invece di bypassare il livello CRUD, introduci alcune opzioni di ottimizzazione in il livello CRUD.

Se il codice CRUD non è scritto a mano, ma generato, è perfettamente possibile estendere il generatore e lasciare che aggiunga le opzioni di ottimizzazione suggerite a tutti i DAO del tuo modello dati.

    
risposta data 31.12.2016 - 10:44
fonte

Leggi altre domande sui tag