Quando si dice "far paginare il DB e non ASP.NET"
Ho preso in mano un'applicazione di un cliente che, purtroppo, faceva uso di paginazione direttamente nel DataGrid (anzi GridView adesso che ha la 2.0) di ASP.NET.
Da sempre consigliamo di non fare paginazione automatica, in quanto in memoria non si riescono a raggiungere le performance di un DB che sfrutta indici e query processor; inoltre, passano più dati dal server DB al server web e non ultimo il carico di memoria sull'applicazione ASP.NET è mostruoso rispetto ai record che l'utente vedrà nelle pagine. Questo ovviamente vale anche per servizi che espongono i dati.
Per una idea delle tecniche utilizzabili su SQL 2000 date un occhio al nostro articolo del http://www.devleap.com/Articolo3723.devleap del 2003. Adesso con SQL 2005 si possono valutare le CTE come ha avuto modo di scrivere Paolo per un articolo uscito su Infomedia e che fra poco possiamo ripubblicare sul sito.
Fin quì niente di nuovo :-) Quello che volevo sottolineare sono i dati di stress test che ho effettuato per questo cliente su SOLI 700 record presentati su una pagina che ne visualizza 10. Il flusso completo prevede uno strato DAL che riempie delle entità di business che vengono poi passato allo strato UI. L'applicazione esistente estraeva 714 record (sono c.a. 8 campi di media lunghezza) tramite Stored Procedure. Lo strato business fa solo da passacarte e lo strato UI visualizza 10 di questi record. Il test che ho fatto non prevede sort (che ovviamente peggiorerebbe ulteriormente il confronto rispetto alla soluzione di far paginare il DB) quindi è il più semplice "tipo di accesso" che l'applicazione può fare.
Vediamo ai numeri:
714 Record - 8 campi di lunghezza variabile (non sono presenti Image...cosa che peggiorebbe ulteriormente il riempimento in memoria su ASP.NET)
25 Utenti in contemporanea che effettuano richieste senza think times (in pratica al termine di una richiesta si procede subito con la successiva)
Durata del test 2 minuti "secchi" per capire le differenze: il cliente è già convinto a paginare dal DB quindi non credo che avrò modo di fare altri test).
Test fatto con VSTS da una seconda macchina per non inficiare i dati globali
Richiesta per la prima pagina di 70, quindi sempre i primi record (cercando gli ultimi i tempi peggiorano con paginazione automatica)
Soluzione precedente (con paginazione da griglia)
1.600 richieste totali
13 richieste al secondo come media (con punte di 27)
100% del processore spesso...e meno male...lo stiamo facendo lavorare
5.8 Average Response Time: con punte di 11,3 massimo
9.398 Garbage Collection a generazione 0
2.626 Garbage Collection a generazione 1
233 MB Memoria media del processo ASP.NET
Soluzione con paginazione fatta dal DB
17.289 richieste totali
143 richieste al secondo come media (con punte di 148)
100% del processore spesso...e meno male...lo stiamo facendo lavorare
0,34 Average Response Time: con punte di 0,45 massimo
9.419 Garbage Collection a generazione 0
1.858 Garbage Collection a generazione 1
206 MB Memoria media del processo ASP.NET
I numeri non hanno bisogno di spiegazioni :-) Siamo oltre 10 volte come numero di richieste nello stesso arco di tempo. Il numero di interventi del GC è simile, ma nel primo caso per servire 1.600 richieste, nel secondo per servirne 17.289, Giusto per curiosità ho provato a limitare il test a 1.600 richieste per il secondo caso....e il GC è intervenuto solo 702 volte.
Quando si fanno le cose però si vanno bene fino in fondo :-) quindi ho provato, per fortuna grazie al generatore di codice GAT implementato, altrimenti ero ancora a scrivere codice, a rendere le pagine e l'accesso ai dati asincrono (per la cronaca sotto c'è SQL 2005).
Soluzione con paginazione fatta dal DB e pagine/ADO asincroni
21.249 richieste totali
177 richieste al secondo come media (con punte di 189)
100% del processore spesso...e meno male...lo stiamo facendo lavorare
0,14 Average Response Time: con punte di 0,15 massimo
9.218 Garbage Collection a generazione 0
1.757 Garbage Collection a generazione 1
206 MB Memoria media del processo ASP.NET
La sfiga, ha voluto che nell'ultimo test ci sia stato un recycle Application Pool di IIS...altrimenti i numeri sarebbero ancora migliori !!!
Questi numeri per dare un senso alle nostre parole di sempre...ricordatevi che stiamo parlando di 714 record (un niente praticamente) e già la differenza è più che abissale; non ci sort che peggiorerebbero i tempi e la memoria da allocare (e quindi ripulire) e tantomeno filtri che rallenterebbero notevolmente quando effettuati in memoria. Per quanto riguarda la parte asincrona, è bene ricordare che un allungamento dei tempi di SQL Server ridurrebbe le prestazioni in misura minore rispetto a pagine sincrone.
Inoltre è doveroso dire che in tutti e tre i test non abbiamo stressato la macchina IIS/ASP.NET in quanto tutte le pagine sono state servite al client: non ci sono in pratica riechieste accodate oltre il limite di default di ASP.NET: se stressassimo ulteriormente il carico le differenze tenderebbero ad aumentare notevolmente...e pensate che il test è solamente con 25 richieste in contemporanea e in sequenza !