2009-08-28 11 views

risposta

9

Un errore che vedo ripetuto più e più volte:

istanziare e la creazione di tutto (DbConnection, DbCommand, DbParameters) all'interno di un metodo che si chiama più volte in un ciclo stretto.

Nella maggior parte dei casi è possibile eseguire il refactoring delle variabili locali come membri della classe che li istanziano una sola volta e mantengono solo gli aggiornamenti di DbParameters all'interno del metodo.


aggiornato per includere il codice di esempio chiesto nei commenti

responsabilità: Questo è un esempio rapido assemblato per l'unico intento di dimostrare il punto sullo spostamento roba ripetitivo fuori dal giro. Altre buone pratiche non sono necessariamente implementate.


     public static void Show() { 
      List people = new List(); 

      //Everything is done inside the loop 
      PersonDal personDal = new PersonDal(); 
      foreach (Person person in people) { 
       personDal.Insert(person); 
      } 

      //Things are setup once outside the loop. 
      using (DbConnection connection = SqlClientFactory.Instance.CreateConnection()) { 
       // setup the connection 
       BetterPersonDal betterPersonDal = new BetterPersonDal(connection); 
       connection.Open(); 
       foreach (Person person in people) { 
        betterPersonDal.Insert(person); 
       } 
      } 
     } 
    } 

    class Person { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

In questa prima implementazione, ogni cosa è istituito ogni volta che il metodo viene chiamato:


class PersonDal { 
    public int Insert(Person person) { 
     DbProviderFactory factory = SqlClientFactory.Instance; 

     using (DbConnection connection = factory.CreateConnection()) { 
      connection.Open(); 

      connection.ConnectionString = "Whatever"; 

      using (DbCommand command = connection.CreateCommand()) { 
       command.CommandText = "Whatever"; 
       command.CommandType = CommandType.StoredProcedure; 

       DbParameter id = command.CreateParameter(); 
       id.ParameterName = "@Id"; 
       id.DbType = DbType.Int32; 
       id.Value = person.Id; 

       DbParameter name = command.CreateParameter(); 
       name.ParameterName = "@Name"; 
       name.DbType = DbType.String; 
       name.Size = 50; 
       name.Value = person.Name; 

       command.Parameters.AddRange(new DbParameter[] { id, name }); 

       return (int)command.ExecuteScalar(); 
      } 
     } 
    } 
} 

ora passiamo il setup per la costruzione degli oggetti lasciando fuori dal giro:


class BetterPersonDal { 
    private DbProviderFactory factory; 
    private DbConnection connection; 
    private DbCommand command; 
    private DbParameter id; 
    private DbParameter name; 

    public BetterPersonDal(DbConnection connection) { 
     this.command = connection.CreateCommand(); 
     this.command.CommandText = "Whatever"; 
     this.command.CommandType = CommandType.StoredProcedure; 

     this.id = command.CreateParameter(); 
     this.id.ParameterName = "@Id"; 
     this.id.DbType = DbType.Int32; 

     this.name = command.CreateParameter(); 
     this.name.ParameterName = "@Name"; 
     this.name.DbType = DbType.String; 
     this.name.Size = 50; 

     this.command.Parameters.AddRange(new DbParameter[] { id, name }); 
    } 

    public int Insert(Person person) { 
     this.id.Value = person.Id; 
     this.name.Value = person.Name; 

     return (int)command.ExecuteScalar(); 
    } 
} 

+0

Esempio incluso –

4

Dai un'occhiata al libro Improving .NET Application Performance and Scalability (disponibile online gratuitamente, in MSDN). C'è un whole chapter sul miglioramento delle prestazioni di ADO.NET.

+0

Link eccellenti. L'unica cosa di cui non sono d'accordo è la loro enfasi sull'utilizzo di stored procedure per le prestazioni. A quanto ho capito, le versioni moderne di SQL Server memorizzano nella cache i piani di esecuzione per le query SQL ad hoc, quindi dopo che una query ad hoc viene eseguita una volta dovrebbe essere veloce come una stored procedure. Tuttavia, l'articolo collegato è in realtà di Microsoft, quindi non ho intenzione di affermare che conosco meglio di loro. In tutti i benchmark che ho fatto ultimamente, tuttavia, le prestazioni delle stored procedure e delle query ad hoc sono praticamente identiche. – MusiGenesis

+1

Un libro davvero ottimo. Ne ho una versione stampata. Sfortunatamente non è stato aggiornato dal 2004 e molte cose sono cambiate. Il backing store di DataRow, ad esempio, è stato completamente riscritto in .Net 2.0, che ha modificato drasticamente il profilo delle prestazioni dell'utilizzo di DataSet tra le versioni 1.xe 2.0. –

2

essere molto intelligente circa la gestione delle connessioni. L'apertura di una connessione DB può essere molto costosa, quindi tienilo a mente quando scrivi il livello di accesso al database.

+4

Questo non dovrebbe essere un problema finché il pool di connessioni è abilitato. L'istanziazione di un oggetto di connessione e la chiamata al suo metodo 'Open' di solito acquisiscono una connessione disponibile dal pool, piuttosto che stabilire una connessione completamente nuova al database. – LukeH

+2

Concordato con Luca. I collegamenti non valgono la pena di preoccuparsi (molto) per più di 10 anni. – MusiGenesis

+0

Ho ottenuto un codice legacy scritto in VB.Net che ha tutto mescolato come se fosse scritto in VB6: nessun livello, nessuna classe, tutto il codice all'interno del modulo e dei moduli base ... –

1

Se non si intende utilizzare un ORM, non vengono memorizzati anche i dati? Questo è un grande vantaggio dell'uso di un ORM. Se non è presente una cache di dati, è necessario esaminare i metodi per memorizzare in cache HTML/JavaScript. Questo può essere ottenuto utilizzando la direttiva OutputCache e SqlDependency. O pubblicando file statici HTML e JavaScript. In entrambi i casi, sarai in grado di gestire un carico maggiore se non esegui costantemente il database su ogni richiesta.

Alcuni link:

ASP.NET Web Site Performance Improvement http://www.codeproject.com/KB/aspnet/aspnetPerformance.aspx

10 ASP.NET prestazioni e scalabilità Segreti http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx

blog

Omar Al Zabir su ASP.NET Ajax e .NET 3.5 http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx

1

L'articolo su Martin è eccellente. Vorrei solo aggiungere che si desidera assolutamente utilizzare un DataReader invece di un DataSet (adoro i DataSet, ma non per ragioni di prestazioni).

+0

A meno che non si debba tornare a record precedenti, nel qual caso l'utilizzo di un DataSet può essere una buona idea. –

+0

@Alfred: ha detto che "vuole che le [s] pagine vengano caricate ad alta velocità", quindi presumo che stia parlando di ASP.Net. In questo caso lasciare che un utente torni ai record precedenti in un DataSet significherebbe memorizzare nella cache il DataSet, che probabilmente non sarebbe una buona idea. – MusiGenesis

+0

@MusiGenesis: Non sono in disaccordo con te. Hai detto che ami i DataSet e sto dando un esempio di quando sono adatti. Anche su una pagina web ad alta velocità * super-duper *, qualcuno potrebbe avere una logica che richiede l'accesso ai record precedenti per qualsiasi ragione aziendale. Invece di tornare al database, utilizzare un DataSet. Nessun DataSet sulla cache - niente da fare. Solo un DataSet utilizzato durante la vita della richiesta. –

Problemi correlati