2012-05-26 16 views
18

Ho un'app per la verifica dell'attrezzo. che utilizza una mappatura fluida di tipo nibernato per l'oggetto db all'interno di mssql db. Dal momento che voglio imparare bene sintonizzare NIB. Applicazioni mvc3, sto usando questa app. a scopo di test che hanno una sola entità semplice con 10 proprietà enum e una proprietà stringa. Quindi, è davvero chiaro come un lampo, ma il tempo di avvio secondo il profiler Nhibernate è di 4.37 secondi. Il che è molto lento per il rendering di un'entità con poche proprietà selezionate/non selezionate.Ottimizzazione della produzione della sessione di nhibere, il tempo di avvio della webApp è molto lento

Il codice è il seguente. Domain.SessionProvider.cs

public static ISessionFactory CreateSessionFactory() 
{ 
    var config = Fluently.Configure() 
      .Database(MsSqlConfiguration.MsSql2008 
      .ConnectionString(c => c.FromConnectionStringWithKey("myConnection"))) 
      .Mappings(m => m.FluentMappings.Add<FeaturesMap>()) 
      .ExposeConfiguration(p => p.SetProperty("current_session_context_class", "web")) 
      .BuildConfiguration(); 

      return config.BuildSessionFactory();    
} 

Global.asax

public class MvcApplication : System.Web.HttpApplication 
{ 
    //SessionPerWebRequest is ommited here as well as other content 
    public static ISessionFactory SessionFactory = 
       SessionProvider.CreateSessionFactory(); 

    protected void Application_Start() 
    { 
     SessionFactory.OpenSession(); 
    } 
} 

All'interno myController ho seguendo:

public ActionResult Index() 
{ 
    return View(GetData()); 
} 

private IList<FeaturesViewModel> GetData() 
{ 
    List<Features> data; 
    using (ISession session = MvcApplication.SessionFactory.GetCurrentSession()) 
    { 
      using (ITransaction tx = session.BeginTransaction()) 
      { 
       data = session.Query<Features>().Take(5).ToList(); 
       tx.Commit(); 

       var viewModelData = FeaturesViewModel.FromDomainModel(data); 
       return viewModelData; 
      } 
     } 
} 
+1

Il tempo di avvio è davvero così importante? In una corretta installazione questo costo non dovrebbe verificarsi spesso. – Lucero

+0

relativo alle app Web. Penso che questo tempo di avvio usando questa entità lightwave sia "qualcosa". Stai dicendo che controllo la distribuzione? – BobRock

+0

Quello che sto dicendo è che se ciò accade una volta al giorno o ogni più giorni in un ambiente distribuito (ogni volta che il pool di applicazioni viene riciclato), tale costo non è un dealbreaker. – Lucero

risposta

19

È possibile migliorare il tempo di avvio (di entrambe le applicazioni Web e Windows) memorizzando nella cache le configurazioni. La seguente classe sarà fare questo lavoro:

using System.IO; 
using System.Reflection; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Web; 
using NHibernate.Cfg; 

namespace NH32AutoMap.Core 
{ 
    public class ConfigurationFileCache 
    { 
     private readonly string _cacheFile; 
     private readonly Assembly _definitionsAssembly; 

     public ConfigurationFileCache(Assembly definitionsAssembly) 
     { 
      _definitionsAssembly = definitionsAssembly; 
      _cacheFile = "nh.cfg"; 
      if (HttpContext.Current != null) //for the web apps 
       _cacheFile = HttpContext.Current.Server.MapPath(
           string.Format("~/App_Data/{0}", _cacheFile) 
           ); 
     } 

     public void DeleteCacheFile() 
     { 
      if (File.Exists(_cacheFile)) 
       File.Delete(_cacheFile); 
     } 

     public bool IsConfigurationFileValid 
     { 
      get 
      { 
       if (!File.Exists(_cacheFile)) 
        return false; 
       var configInfo = new FileInfo(_cacheFile); 
       var asmInfo = new FileInfo(_definitionsAssembly.Location); 

       if (configInfo.Length < 5 * 1024) 
        return false; 

       return configInfo.LastWriteTime >= asmInfo.LastWriteTime; 
      } 
     } 

     public void SaveConfigurationToFile(Configuration configuration) 
     { 
      using (var file = File.Open(_cacheFile, FileMode.Create)) 
      { 
       var bf = new BinaryFormatter(); 
       bf.Serialize(file, configuration); 
      } 
     } 

     public Configuration LoadConfigurationFromFile() 
     { 
      if (!IsConfigurationFileValid) 
       return null; 

      using (var file = File.Open(_cacheFile, FileMode.Open, FileAccess.Read)) 
      { 
       var bf = new BinaryFormatter(); 
       return bf.Deserialize(file) as Configuration; 
      } 
     } 
    } 
} 

da usare che,

private Configuration readConfigFromCacheFileOrBuildIt() 
{ 
    Configuration nhConfigurationCache; 
    var nhCfgCache = new ConfigurationFileCache(MappingsAssembly); 
    var cachedCfg = nhCfgCache.LoadConfigurationFromFile(); 
    if (cachedCfg == null) 
    { 
     nhConfigurationCache = buildConfiguration(); 
     nhCfgCache.SaveConfigurationToFile(nhConfigurationCache); 
    } 
    else 
    { 
     nhConfigurationCache = cachedCfg; 
    } 
    return nhConfigurationCache; 
} 

E poi prima di chiamare il BuildSessionFactory, siamo in grado di leggere il file di configurazione dalla cache o se le mappature sono cambiati, costruirlo e memorizzare nella cache di nuovo:

public ISessionFactory SetUpSessionFactory() 
{ 
    var config = readConfigFromCacheFileOrBuildIt(); 
    var sessionFactory = config.BuildSessionFactory(); 

Qui trovi un campione completo: (^). + Se si desidera farlo funzionare, separare le classi di dominio e gli assembly delle definizioni dei mapping dall'assembly dell'applicazione principale (poiché la classe ConfigurationFileCache eliminerà il file della cache se l'assembly delle definizioni dei mapping è più recente di LastWriteTime del file della cache).

+0

FYI: Ho provato questo su 3.3 e non fa differenza. Forse il mio SSD è più veloce dei vecchi HD, ma il problema all'avvio rimane. – Candide

2

IIRC correttamente, non è una buona idea creare oggetti nel contructor di HttpApplication (o nelle sue sottoclassi come MvcApplication) . È meglio creare la factory di sessione nel gestore Application_Start.

È necessario rimuovere il profiler NHibernate (poiché tutti i profiler potrebbero influire sulle misurazioni). Invece, metti la chiamata a CreateSessionFactory() e circondala con l'uso della classe Cronometro per ottenere una misurazione accurata.

Il server del database risponde lentamente? A causa del pool di connessioni, questo potrebbe essere visibile solo alla prima occasione.

NHibernate richiede un po 'di tempo per l'inizializzazione, ma 4 secondi con un'entità leggera sembrano troppo. Ciò è ovviamente influenzato dalle prestazioni generali del sistema di test.

+0

avendo in mente questo codice, posso chiederti di mostrarmi come dovrebbe apparire il metodo Application_Start. Grazie – BobRock

+0

In relazione al tuo codice originale, sposta la chiamata a CreateSessionFactory() in Application_Start() e la chiamata a OpenSession() in Application_BeginRequest(). Aggiungi il codice adatto per chiudere la sessione in Application_EndRequest(). L'utilizzo di Begin | EndRequest corrisponde al pattern session-per-request. –

Problemi correlati