Progettazione di un'applicazione di database con OOP

5

Spesso sviluppo applicazioni di database SQL utilizzando Linq e la mia metodologia consiste nel costruire classi di modelli per rappresentare ogni tabella e ogni tabella che deve essere inserita o aggiornata ottiene un metodo Save () (che fa anche InsertOnSubmit () o SubmitChanges ( ), a seconda dello stato dell'oggetto). Spesso, quando devo rappresentare una raccolta di record, creerò una classe che eredita da un oggetto tipo List della classe atomica.

es.

public class CustomerCollection : CoreCollection<Customer>
{

}

Recentemente, stavo lavorando a un'applicazione in cui gli utenti finali stavano vivendo una lentezza, in cui ciascuno degli oggetti doveva essere salvato nel database se rispondevano a determinati criteri. Il mio metodo Save () era lento, presumibilmente perché stavo facendo tutti i tipi di round trip sul server e chiamando DataContext.SubmitChanges () dopo ogni salvataggio atomico.

Quindi, il codice potrebbe essere stato simile a questo

foreach(Customer c in customerCollection)
{
   if(c.ShouldSave())
   {
       c.Save();
   }
}

Ho lavorato su più strategie per ottimizzare, ma alla fine ho deciso di passare una grande stringa di dati a una stored procedure SQL, in cui la stringa ha tutti i dati che rappresentano i record con cui stavo lavorando: potrebbe essere qualcosa del genere:

CustomerID:34567;CurrentAddress:23 3rd St;CustomerID:23456;CurrentAddress:123 4th St

Quindi, SQL Server analizza la stringa, esegue la logica per determinare l'appropriatezza del salvataggio e quindi Inserisce, Aggiorna o Ignora.

Con C # / Linq che esegue questo lavoro, ha salvato 5-10 record / s. Quando SQL lo fa, ottengo > 100 record / s, quindi non si può negare che Stored Proc sia più efficiente; tuttavia, odio la soluzione perché non sembra quasi pulita o sicura.

La mia vera preoccupazione è che non ho soluzioni migliori che tengano una candela alle prestazioni della soluzione proc memorizzata. Sto facendo qualcosa di evidentemente sbagliato nel modo in cui sto pensando di progettare applicazioni di database? Ci sono modi migliori per progettare applicazioni di database?

    
posta Tim C 17.10.2012 - 18:03
fonte

4 risposte

2

Nelle moderne versioni di SQL Server (> 2008 IIRC) è possibile utilizzare i tipi definiti dall'utente. Quindi il tuo sproc può effettivamente assumere una serie di tipi di utenti:

link

Nella nostra app usiamo effettivamente il pattern del repository, ma lo modifichiamo un po 'per aggirare problemi di lentezza come descrivi.

Quindi, nel tuo esempio, farei qualcosa del genere:

using (CustomerBulkContext ctx = customerCollection.GetSaveContext())
{

foreach(Customer c in customerCollection)
{
   if(c.ShouldSave())
   {
       c.Save(ctx);
   }
}
ctx.Save();
}

L'idea è che tutti i clienti vengano aggiunti a un elenco in memoria all'interno del contesto, quindi il commit effettivo sul DB viene gestito tramite il metodo .Save () del contesto di salvataggio. Questo metodo crea quindi un elenco di oggetti SQL e li passa a un comando che esegue l'aggiornamento / inserimento / eliminazione collettiva.

    
risposta data 17.10.2012 - 20:35
fonte
2

Una "regola per pollice" per ottenere una velocità incredibile in un database consiste nell'usare comandi basati su set invece di comandi di stile procedurale separati. Non sono solo i round trip della rete che influenzano le prestazioni. Anche se hai il ciclo incorporato in sql, troverai ordini di grandezza più lenti di un comando basato su set.

--SLOW way, procedural
loop i=0 to 999999
    update foobar set status='test' where id=i;
end loop

vs

--FAST way, set-based
update foobar set status='test' where id between 0 and 999999

Ovunque si vedano i dati elaborati in un ciclo, è possibile sostituirlo con comandi basati su set. Se ci sono condizioni mutevoli controllate a metà loop, potresti essere costretto a usare lo stile procedurale. Ma questo è molto raro.

Identifica semplicemente i colli di bottiglia. Puoi mantenere il resto della logica controllata con i tuoi oggetti. Se lavori solo su un singolo record, lo stile procedurale è altrettanto veloce.

NOTA: internamente all'interno dell'RDBMS i comandi "set-based" sono eseguiti tramite un loop procedurale. Niente di male con i loop per dire, è solo l'interfaccia fornita dalla maggior parte degli RDBMS sono ottimizzati per essere usati con comandi basati su set.

    
risposta data 17.10.2012 - 21:17
fonte
1

Vorrei prendere in considerazione l'utilizzo di una delle soluzioni ORM di grande nome come Entity Framework o NHibernate. Il vantaggio di farlo è che eseguono tutti i tipi di trucchetti per ottimizzare i risultati nel database. Ad esempio:

  1. Memorizzazione nella cache, quindi è necessario leggere i valori dal database una volta.
  2. Le modifiche al monitoraggio, quindi aggiornano solo i campi effettivamente modificati.
  3. Caricamento lento, quindi leggono solo i record di una raccolta quando li usi effettivamente.

Inoltre, non sarai legato a una singola tabella per classe (il cosiddetto pattern "record attivo").

I lati negativi del mio suggerimento sono che la tua base di codice esistente avrà bisogno di qualche (forse considerevole) modifica, e hai una curva di apprendimento ripida prima di te.

Tuttavia, avendo fatto anch'io un viaggio simile, sono convinto che questa sia una direzione utile per il viaggio.

    
risposta data 17.10.2012 - 21:22
fonte
0

Quando elabori un elenco di record, invece di chiamare c.Save() devi passarli a una sorta di aggregatore in grado di analizzare i record e scrivere le istruzioni SQL appropriate (oppure le tue classi possono semplicemente supportare un emitDML() metodo che restituisce l'SQL da eseguire). Quindi, una volta terminato l'elenco, è sufficiente comunicare all'aggregatore di mantenere le eventuali modifiche e di eseguire l'SQL in un'unica transazione. Se hai a che fare con centinaia di record, potrebbe essere sensato serializzarli su disco e invocare il programma di copia di massa per inserirli, ma è una buona quantità di lavoro.

    
risposta data 17.10.2012 - 23:21
fonte

Leggi altre domande sui tag