Dovresti abbandonare un framework ORM quando devi implementare un'operazione in blocco?


15

Ecco una situazione comune:

  • È necessario implementare un'operazione in blocco in un'applicazione che utilizza un framework ORM.
  • Dopo il primo passaggio, hai notato significativi problemi di prestazioni.

Ecco la mia domanda:

  • In questa situazione, dovresti favorire una soluzione che includa SQL raw?
  • Oppure ci sono modelli di progettazione noti che possono aiutarti a mitigare i problemi che sono comunemente associati alle operazioni di massa con i framework ORM?

MODIFICARE:

  • Non sto chiedendo se è necessario rimuovere il framework ORM dall'intera applicazione.
  • Sto chiedendo: dovresti rinunciare al framework ORM per questa piccola parte dell'applicazione?

Non so se dovresti fare qualcosa, ma hai provato a raggruppare l'operazione in blocco?
ChrisAnnODell,

Risposte:


13

Gli ORM non intendono assumere completamente l'accesso al database. Usali per quell'80% di codice che è CRUD, il materiale troppo noioso per scrivere da solo. Utilizzare stored procedure, SQL dinamico o qualsiasi altra cosa si desideri per il restante 20% che deve essere attentamente ottimizzato.


4
Funzionerebbe se l'astrazione del database non fosse uno dei motivi principali per cui hai deciso di utilizzare un ORM.

@ Pierre303, ho difficoltà a capire il tuo commento. Cosa intendi?
Mark Canlas,

@MarkCanlas: Penso che significhi "sottrarre il database", nel senso che si potrebbe cambiare il database (ad esempio passare da SQL Server a MySQL) se si desidera farlo. In pratica, questo caso d'uso non si verifica quasi mai.
Robert Harvey,

1
Puoi ancora creare astrazioni. La maggior parte degli ORM che attualmente supportano più provider / dialetti ha il supporto per codice specifico del provider / dialetto. È possibile implementare operazioni come inserimento di massa / associazione array / TVP / qualunque cosa per database specifici e lasciarlo tornare lentamente a rallentamento per i provider non supportati come SQLite. Nel peggiore dei casi è possibile suddividere la funzionalità che potrebbe essere alla rinfusa in un'interfaccia / classe separata e in una diversa implementazione basata su parametri build o config.
Aaronaught l'

Sì, i dialetti personalizzati possono aiutare, così come il codice specifico per problemi specifici. Tuttavia, affinché ciò sia praticabile dal punto di vista finanziario, questo deve essere limitato al minimo indispensabile. La nostra personalizzazione tramite funzioni personalizzate (dialetti) rappresenta meno dello 0,1% della base di codice di accesso ai dati totale. Sarei davvero preoccupato se fosse più di questo.

7

Uso un ORM (nHibernate) in un'applicazione che richiede prestazioni elevate e gestisce miliardi di record. Con il passare del tempo abbiamo notato che i problemi di prestazioni più significativi erano legati al nostro modo di usare l'ORM piuttosto che al solo ORM.

L'ORM non deve sostituire la conoscenza del database obbligatoria. È uno strumento che usi per ottenere maggiore produttività e flessibilità nel tuo codice, ma dovrai conoscere i processi sottostanti per ottimizzare le tue prestazioni.

Non hai specificato un ORM specifico, quindi ecco le cose che abbiamo fatto per migliorare le prestazioni:

  • Abbiamo usato un profiler ORM. (abbiamo usato nhprof)
  • Abbiamo usato un profiler di database. (abbiamo usato SQL Server Profiler)
  • Leggiamo quanti più articoli possibile sull'argomento. (Molti erano disponibili per nHibernate in aggiunta all'intero capitolo sull'argomento nella documentazione)
  • Abbiamo acquistato libri specifici su prestazioni e scalabilità.
  • Abbiamo creato un sistema di benchmarking per testare le nostre ottimizzazioni.
  • e ancora più importante, siamo stati in grado di testare il nostro codice con clienti reali con dati enormi. Quest'ultima cosa da sola ci ha aiutato a individuare la maggior parte dei problemi nella nostra applicazione.

1

Siamo riusciti a farlo con Entity Framework, ma la nostra applicazione ha eseguito molte operazioni in stile batch (scrivevamo un gran numero di record su singole tabelle), quindi è stata una buona scelta. Vedrei sicuramente se sarebbe possibile conservare il framework ORM, se possibile, solo per ridurre la quantità di codice speciale nella tua app. È possibile bufferizzare le scritture, quindi eseguirle come gruppo? Perdi la semantica delle transazioni, ma se stai andando con operazioni collettive suppongo che tu abbia già fatto i conti con quello.


1

Gli ORM non fanno nulla di magico. Traducono i metodi di accesso agli oggetti in SQL. Le istruzioni SQL che eseguono non sono necessariamente più lente dell'SQL che scriveresti manualmente. Detto questo, ci sono alcuni problemi sui quali potresti imbatterti:

  1. Transazioni: una grande operazione in blocco è quasi sempre più veloce di molte piccole transazioni che insieme compiono la stessa cosa. Pertanto, se le chiamate del metodo ORM utilizzano transazioni a grana fine (ad esempio i metodi di stile record attivi nelle entità Spring Roo sono annotati come @Transactional per impostazione predefinita), le operazioni in blocco saranno lente. In tal caso nell'applicazione, è necessario esaminare la logica della transazione.
  2. Memorizzazione nella cache: in Hibernate, una cache di primo livello consente al gestore dell'entità di evitare round trip inutili nel database. Buona cosa in generale, ma cattiva per gli inserti di massa, dove porta ad un occultamento inutile della cache, con conseguente degrado delle prestazioni dell'applicazione. Se questo è il tuo problema, dovresti esaminare il modello di batch suggerito sopra da ChrisAnnODell. Lo usiamo nei nostri importatori e accelera molto gli inserti sfusi.

Non c'è niente di sbagliato nell'usare SQL nativo per migliorare le prestazioni. Ma prima assicurati di capire cosa ti sta rallentando.


Per evitare la cache, utilizzare StatelessSession. Inoltre, evitare gli ID di incremento automatico. In alternativa, utilizzare HiLo o Guid.

1

Bypassare l'ORM. Non solo, ma ignora anche il "normale" sql. Utilizzare un'utilità di massa del database per inserire set di dati estremamente grandi in una tabella di gestione temporanea. Quindi utilizzare sql per eseguire le attività di gestione temporanea.

Il tuo ORM "sapore del blog" potrebbe non funzionare in tutte le situazioni.


Bene, questo tipo di strumenti di back-end è una seccatura da imparare, ma dopo circa 3 o 4 volte, sarai un esperto e puoi fare cose più velocemente e talvolta cose che non possono essere fatte in altri modi. È come la differenza tra una pala e un bulldozer. Ho scritto strumenti controllati da script per varie piattaforme per leggere file di input di testo e aggiornare i dati con operazioni di basso livello. Scrivere un tale strumento può anche semplificarti la vita (o almeno più interessante). Cose come questa possono essere utilizzate per modificare i dati di personalizzazione sulle installazioni client durante gli aggiornamenti del software.

0

Sono stato in quella situazione. A volte, devi.

Alcuni ORM consentono allo sviluppatore di saltare il modello a oggetti e passare direttamente al livello del database.

Esistono anche ORM, che utilizzano operazioni in blocco, incapsulate, come orientate agli oggetti.


0

Come menzionato da umlcat , ci sono alcuni ORM che ti permetteranno di usare operazioni in blocco.

Ancora meglio, molti ORM sono estensibili, quindi puoi semplicemente scrivere il tuo metodo per eseguire operazioni in blocco, se non già supportato. Se l'operazione di massa nella tua applicazione è qualcosa che puoi prendere in considerazione, la aggiungerei come livello sull'ORM (per farlo, probabilmente dovrai scrivere SQL grezzo), ma poi nell'applicazione, usa l'ORM metodo che hai implementato.

Ciò semplifica anche il test di unità e il debug. Una volta che hai una buona copertura di prova per i tuoi metodi ORM, sei libero di usarlo nelle tue app. Altrimenti, il debug di SQL non elaborati (soprattutto quelli di grandi dimensioni con transazioni e molti JOIN) può essere una seccatura.

Una volta mi ci è voluto quasi un giorno per individuare un bug in una chiamata SQL non elaborata che era quasi 100 LOC e il bug era solo un singolo carattere! Da allora, provo ad evitare di avere SQL raw nell'app e di avere tutte le procedure SQL testate separatamente dall'unità.


0

Beh, non ci sono schemi di design di cui sono a conoscenza. La mia ipotesi è che tu abbia preso la decisione per l'ORM per un motivo, quindi abbandonare l'ORM probabilmente non è quello che vuoi. Tuttavia, in questi casi penso che ci sia spazio per mescolare entrambe le soluzioni. Non c'è nulla di sbagliato in questo, a condizione che lo faccia coscientemente e documenti perché ti discosti dall'uso predefinito dell'ORM nel tuo software. Accanto a ciò, alcuni framework ORM hanno alcune strutture per eseguire operazioni in blocco. So che nHibernate (ORM per il framework .NET) ha chiamato StatelessSessions, che ha molte meno spese generali, ma questo potrebbe ancora non darti la spinta delle prestazioni che stai cercando. In tal caso, utilizzare solo SQL non elaborato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.