2010-02-01 14 views
5

Sto utilizzando NHibernate per ORM e ho consolidato il caricamento di molte entità in un'unica grande query.La latenza di NHibernate è molto alta

In realtà sto caricando un dizionario di parole, circa 500.000 voci e ogni parola si riferisce ad altre. L'esecuzione del processo di caricamento in background potrebbe essere molto complicata nella nostra applicazione, in quanto dovremmo caricare manualmente una voce che non è stata caricata in tempo, poiché qualsiasi parola potrebbe essere richiesta in qualsiasi momento. I nostri unici requisiti sono che tutti i dati vengano caricati il ​​più velocemente possibile. Ho anche provato ad usare una sessione senza stato, ma ho ottenuto un'eccezione che le sessioni stateless non possono recuperare le raccolte (per qualche motivo, forse ha a che fare con il fatto che non ci sono cache per le sessioni stateless?)

Il problema è che sebbene la query richieda non più di 25 secondi in SQLServer, occorrono oltre 3 minuti per ICriteria.List().

Ho utilizzato NHProf per profilare il processo di caricamento e ho scoperto che la creazione delle entità è un'operazione costosa, che occupa la maggior parte del tempo di caricamento in NHibernate.

C'è qualcosa che posso fare per ridurre questa latenza? L'allocazione di memoria è costosa o è la "compilazione" dei dati?

Grazie!

risposta

0

La definizione del profilo del processo di creazione (ad esempio con l'analizzatore di prestazioni VS) dovrebbe indicare esattamente qual è l'operazione costosa. Se hai già giocato con il pigro tuning del caricamento, penso che l'unica buona soluzione sia quella di incapsulare l'elenco restituito per abilitare il paging e restituire blocchi più piccoli in poche iterazioni. Non sono sicuro che NHibernate supporti liste di risultati pigri come fa JPA (cioè non carica le entità dal lettore di dati finché non è necessario).

4

Forse dovresti considerare il fatto che NHibernate (come la maggior parte degli ORM) non è particolarmente adatto (o previsto) per questi tipi di scenari di caricamento di massa. Quante righe stai cercando di caricare, dare o prendere? Cosa stai cercando di fare? Pre-popola una cache? Elaborazione batch-like?

Il mio istinto è che dovresti considerare seriamente lo scopo della tua app e scegliere le tecnologie sottostanti di conseguenza. Forse puoi far luce sulle tue intenzioni/requisiti?

MODIFICA OK, dai tuoi commenti capisco cosa stai cercando di fare qui. La prima cosa che farei è creare un semplice prototipo utilizzando raw ADO.NET per caricare gli stessi dati, per avere un'idea delle migliori prestazioni ottenibili utilizzando l'accesso ai dati standard e le raccolte in memoria. Successivamente, giocherellare con diversi tipi di raccolta per vedere cosa si comporta bene quando si popola e si cerca. Se il caricamento di dati come questo è ancora troppo lento, è tempo di iniziare a cercare altri metodi di caricamento dei dati: basato su file da un file di dati locale, idratazione di oggetti pre-serializzati, qualche forma di caricamento veloce su richiesta, ecc.

+0

Grazie per la rapida risposta! Sto provando a caricare più di 500K righe, ognuna delle quali è un'entità. Ogni entità può puntare ad altre entità. Sto cercando di popolare questa lista il più velocemente possibile con tutte queste relazioni interpersonali. Non sto scrivendo nulla sul DB, ma dopo aver sperimentato con il caricamento pigro, ho trovato che non soddisfa i miei bisogni. La prossima cosa migliore che potrei pensare è in qualche modo caricare i dati in un thread diverso in una sorta di modello produttore-consumatore, ma non ho idea di come lo si faccia. Qualche idea? Avete suggerimenti per altre tecnologie? Grazie! –

+1

Non ho ancora idea del motivo per cui vorrai caricare così tante entità correlate. Ciò rende difficile dare suggerimenti. Caricare i dati in background può avere senso, ma solo se la tua app può iniziare a fare tutto ciò che è necessario fare senza tutti i dati in atto. In breve, dicci cosa vuoi ottenere, quali sono le tue esigenze, forse allora possiamo darti un suggerimento adeguato o due. – tijmenvdk

+0

In realtà sto caricando un dizionario di parole, quando ogni parola si riferisce ad altri. La cosa di sfondo potrebbe essere molto complicata nella nostra applicazione, in quanto dovremmo caricare manualmente una voce che non è stata caricata prima. Il problema è che una di quelle parole potrebbe essere richiesta in qualsiasi momento. I nostri unici requisiti sono che tutti i dati vengano caricati il ​​più velocemente possibile. Ho anche provato ad usare una sessione senza stato, ma ho ottenuto un'eccezione nel fatto che le sessioni stateless non possono recuperare le raccolte ... –

3

Caricamento di entità 500k in una sessione di NHibernate non è una buona idea. La sessione è fatta per essere di breve durata e contenere un numero relativamente piccolo di entità.

Se si desidera eseguire questo tipo di elaborazione in batch in NHibernate, è necessario dare un'occhiata a StatelessSession anziché alla sessione ordinaria. L'utilizzo di una sessione senza stato molto probabilmente migliorerebbe drasticamente le prestazioni in questo scenario. Tuttavia, quando si utilizza una sessione senza stato si perdono i benefici della cache di primo livello di NHibernate, ad esempio il rilevamento delle modifiche.

Ulteriori informazioni su StatelessSession sono disponibili in this article e in the NH docs su nhibernate.info.

In questo scenario, si consiglia inoltre di considerare l'utilizzo di ADO.NET normale anziché di NHibernate. Non sto dicendo che dovresti cambiare tutta la tua strategia di accesso ai dati su ADO.NET ma potresti prendere in considerazione l'utilizzo di ADO.NET per le operazioni batch e l'utilizzo di NHibernate per gli altri casi.

+0

Grazie. Ho provato a utilizzare una sessione senza stato, ma ho ricevuto il seguente errore: SessionException: "le raccolte non possono essere recuperate da una sessione senza stato". Perché questo dovrebbe essere vero? C'è un modo per aggirare questo? –

+1

Se è davvero necessario caricare le entità con le loro raccolte secondarie popolate, StatelessSession non si adatta bene, poiché ignora le raccolte (in base ai documenti di NHForge). La ragione di ciò è probabilmente che StatelessSession è implementato a un livello molto più vicino a ADO.NET rispetto alla sessione ordinaria. Sembra che ADO.NET sia una scelta migliore di NHibernate nel tuo scenario. –