Domanda

Ho un'applicazione che utilizza NHibernate come ORM e talvolta riscontra problemi di prestazioni a causa del modo in cui accede ai dati.Che tipo di cose si possono fare per migliorare le prestazioni di NHibernate?(Si prega di limitare a una raccomandazione per risposta)

È stato utile?

Soluzione

Il primo e più drammatico problema di prestazioni che puoi incontrare con NHibernate è se stai creando una nuova session factory per ogni sessione che crei.È necessario creare una sola istanza della factory di sessione per ogni esecuzione dell'applicazione e tutte le sessioni devono essere create da quella factory.

In questo senso, dovresti continuare a utilizzare la stessa sessione finché ha senso.Questo varierà in base all'applicazione, ma per la maggior parte delle applicazioni Web è consigliata una singola sessione per richiesta.Se elimini frequentemente la tua sessione, non otterrai i vantaggi della sua cache.Utilizzando in modo intelligente la cache della sessione è possibile modificare una routine con un numero lineare (o peggiore) di query in un numero costante senza molto lavoro.

Altrettanto importante è assicurarsi di caricare in modo pigro i riferimenti agli oggetti.In caso contrario, potrebbero essere caricati interi grafici di oggetti anche per le query più semplici.Ci sono solo alcuni motivi per non farlo, ma è sempre meglio iniziare con il caricamento lento e tornare indietro quando necessario.

Questo ci porta al recupero impaziente, l'opposto del caricamento pigro.Mentre si attraversano le gerarchie di oggetti o si scorre attraverso le raccolte, può essere facile perdere traccia di quante query si stanno effettuando e ci si ritrova con un numero esponenziale di query.Il recupero più intenso può essere eseguito in base alla query con un FETCH JOIN.In rare circostanze, ad esempio se esiste una particolare coppia di tabelle a cui raccogli sempre l'unione, valuta la possibilità di disattivare il caricamento lento per quella relazione.

Come sempre, SQL Profiler è un ottimo modo per trovare query lente o eseguite ripetutamente.Nel mio ultimo lavoro avevamo una funzionalità di sviluppo che contava anche le query per richiesta di pagina.Un numero elevato di query per una routine è l'indicatore più evidente che la tua routine non funziona bene con NHibernate.Se il numero di query per routine o richiesta sembra buono, probabilmente sei interessato alla messa a punto del database;assicurandoti di avere memoria sufficiente per archiviare piani di esecuzione e dati nella cache, indicizzare correttamente i tuoi dati, ecc.

Un piccolo problema complicato che abbiamo riscontrato riguardava SetParameterList().La funzione consente di passare facilmente un elenco di parametri a una query.NHibernate ha implementato questo creando un parametro per ogni elemento passato.Ciò si traduce in un piano di query diverso per ogni numero di parametri.I nostri piani di esecuzione venivano quasi sempre rilasciati dalla cache.Inoltre, numerosi parametri possono rallentare notevolmente una query.Abbiamo eseguito un hack personalizzato di NHibernate per inviare gli elementi come un elenco delimitato in un singolo parametro.L'elenco era separato in SQL Server da una funzione di valore di tabella che il nostro hack ha inserito automaticamente nella clausola IN della query.Potrebbero esserci altre mine terrestri come questa a seconda dell'applicazione.SQL Profiler è il modo migliore per trovarli.

Altri suggerimenti

SessionFactory di NHibernate è un'operazione costosa, quindi una buona strategia è creare un Singleton che garantisca che ci sia solo UNA istanza di SessionFactory in memoria:

   public class NHibernateSessionManager
    {
        private readonly ISessionFactory _sessionFactory;

        public static readonly NHibernateSessionManager Instance = new NHibernateSessionManager();

        private NHibernateSessionManager()
        {
            if (_sessionFactory == null)
            {
                System.Diagnostics.Debug.WriteLine("Factory was null - creating one");
                _sessionFactory = (new Configuration().Configure().BuildSessionFactory());
            }
        }

        public ISession GetSession()
        {
            return _sessionFactory.OpenSession();
        }

        public void Initialize()
        {
            ISession disposeMe = Instance.GetSession();
        }
    }

Quindi nel tuo Global.Asax Application_Startup, puoi inizializzarlo:

protected void Application_Start()
{
    NHibernateSessionManager.Instance.Initialize();
}

Evitare e/o minimizzare il Seleziona N + 1 problema riconoscendo quando passare dal caricamento lento al recupero desideroso per le query a esecuzione lenta.

Nessuna raccomandazione ma uno strumento per aiutarti:NH Prof ( http://nhprof.com/ ) sembra essere promettente, può valutare l'utilizzo del framework ORM.Può essere un buon punto di partenza per la messa a punto di NHibernate.

Senza alcuna specifica sui tipi di problemi di prestazioni riscontrati, posso solo offrire una generalizzazione:Nella mia esperienza, la maggior parte dei problemi di prestazioni delle query sul database derivano dalla mancanza di indici adeguati.Quindi il mio suggerimento per una prima azione sarebbe quello di controllare i tuoi piani di query per le query non indicizzate.

NHibernate genera SQL piuttosto veloce immediatamente.Lo uso da un anno e non ho ancora dovuto scrivere SQL nudo con esso.Tutti i miei problemi di prestazioni provengono da Normalizzazione e mancanza di indici.

La soluzione più semplice è esaminare i piani di esecuzione delle tue query e creare indici adeguati, in particolare sulle colonne di chiave esterna.Se si utilizza Microsoft SQL Server, il "Database Engine Tuning Advisor" è di grande aiuto in questo senso.

Solo "Una raccomandazione per risposta"?Allora opterei per questo:

Evitare i duplicati di join (prodotti cartesiani AKA) dovuti a join lungo due o più associazioni parallele a molti;utilizzare invece Exists-subqueries, MultiQueries o FetchMode "subselect".

Preso da: Suggerimenti per l'ottimizzazione delle prestazioni di ibernazione

Posso limitare la mia risposta a una sola opzione?In tal caso selezionerei di implementare il meccanismo di cache di secondo livello di NHibernate.

In questo modo, per ogni oggetto nel tuo file di mappatura puoi definire la strategia della cache.La cache di secondo livello manterrà in memoria gli oggetti già recuperati e quindi non effettuerà un altro viaggio di andata e ritorno verso il database.Questo è un enorme miglioramento delle prestazioni.

Il tuo obiettivo è definire gli oggetti a cui la tua applicazione accede costantemente.Tra questi ci saranno le impostazioni generali e simili.

È possibile trovare molte informazioni sulla cache di secondo livello di nhibernate e su come implementarla.

Buona fortuna :)

Caching, Caching, Caching: stai utilizzando correttamente la memorizzazione nella cache di primo livello [chiudendo le sessioni prematuramente o utilizzando StatelessSession per ignorare la memorizzazione nella cache di primo livello]?Hai bisogno di impostare una semplice cache di secondo livello per i valori che cambiano raramente?È possibile memorizzare nella cache i set di risultati delle query per velocizzare le query che cambiano raramente?

[Anche la configurazione: puoi impostare gli elementi come immutabili?Puoi ristrutturare le query per riportare solo le informazioni che ti servono e trasformarle nell'entità originale?Riuscirà Batman a fermare l'Enigmista prima che raggiunga la diga?...oh, scusa, mi sono lasciato prendere la mano.]

La profilazione è il primo passo – anche semplici test unitari cronometrati – per scoprire dove si possono ottenere i maggiori guadagni

Per le raccolte, considerare l'impostazione della dimensione del batch per ridurre il numero di istruzioni select emesse - vedere la sezione Miglioramento delle prestazioni per dettagli

Se non stai già utilizzando il caricamento lento (appropriatamente), inizia.Recuperare le raccolte quando non ti servono è uno spreco di tutto.

Capitolo Miglioramento delle prestazioni descrive questo e altri modi per migliorare le prestazioni.

Cosa ha detto muchoffreetime.

Leggere il capitolo 19 della documentazione, "Migliorare le prestazioni".
Ibernazione: http://nhibernate.info/doc/nhibernate-reference/performance.html
Ibernazione: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

Utilizza SQL Profiler (o equivalente per il database che stai utilizzando) per individuare le query con esecuzione prolungata.Ottimizza tali query con indici appropriati.

Per le chiamate al database utilizzate su quasi ogni singola pagina di un'applicazione, utilizzare CreateMultiQuery per restituire più set di risultati da una singola query del database.

E, naturalmente, cache.La direttiva OutputCache per pagine/controlli.Caching di Hibernate per i dati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top