Roberto Brunetti

Developing in the cloud

.NET Programming

Archives

Le Regole d'Oro per lo sviluppo mobile - Secondo Episodio

Ho ricevuto diverse mail sul primo episodio  con richieste di chiarimenti, soprattutto per il punto apertura connessioni; ho pensato di fare velocemente un secondo episodio sul tema:

Questo è quanto ho scritto a riguardo:

 

  • Fare poche Open/Close al DB
    • Con SQLCE il costo di apertura e chiusura di una connessione è alto
    • Non esiste Connection Pooling per SQLCE
    • Conviene quindi lasciare aperta la connessione al DB se si cercano le prestazioni
    • Tenere quindi le connessioni statiche (con un singleton magari) nel Dal Layer
    • E' anche vero che se le connessioni devono essere più di una (lavoriamo in multithread eseguendo operazioni in parallelo) diventa più complicata la loro gestione (e chiusura).
      • Spesso, se non sono alla canna del gas, apro e chiudo le connessioni ogni volta
      • Avendo un generatore di codice diventa semplice modificare questo comporamento
      • Le connessioni comunque pesano quindi in applicazioni multi-thread pesare bene queste considerazioni
  •  

    Come indicavo nell'ultimo punto, è importante pesare bene queste considerazioni; le performance sono importanti ed è importante cercare di massimizzarle nei punti critici dell'applicazione; è altrettanto importante la manutenibilità del codice e la valutazione delle controindicazioni.

    Tenere aperte le connessioni significa migliorare le performance ma

    1. Spesso, in una applicazione, le operazioni che usano i dati fanno parte di un processo più ampio che parte con una azione da parte dell'utente; le performance percepite dall'utente in questo caso sono la cosa più imporante.
      1. Se riempiamo una griglia con 20 record paginati da una tabella con migliaia di record sicuramente il tempo di refresh della UI e il recupero delle informazioni (l'esecuzione della query) sono superiore all'apertura e chiusura della connessione
      2. Se l'operazione sui dati non è immediata (oltre 1 secondo per capirci) il tempo di apertura e chiusura è abbastanza ininfluente
    2. Normalmente i database SDF stanno su una memory card (Compact Flash o SD che sia) e spesso il palmare va in stand-by (GIUSTAMENTE) durante l'utilizzo: la filosofia su Windows CE consiste proprio nel sospendere e ripartire dall'esatto punto in cui si è lasciato il device questo vale per Pocket Outlook così come per le nostre applicazioni
      1. Se non usiamo il device, probabilmente il Power Save stacca la scheda SD per risparmiare batteria. Se abbiamo una connessione aperta è molto probabile che venga persa e l'applicazione non sia utilizzabile se non riaprendo la connessione
      2. Ancora peggio è utilizzare un SqlCeResultSet in binding su un controllo della user interface: in questo caso la connessione si perde durante lo stand-by o lo spegnimento della shceda...con un errore non proprio carino per l'utente...rivedere il primo episodio per altri problemi (prestazioni comprese) di un SqlCeResultSet
    3. Una connessione sempre aperta porta anche a "problemi" di organizzazione: ad esempio occorre chiuderla prima di una operazione di Compact, Repair, Verify
    4. In generale, come dicevo nel primo episodio, è vero che dal punto di vista delle performance pure converrebbe tenere sempre aperta una connessione, ma è altrettanto vero che i contro non sono pochi. Tutti "i contro" possono essere risolti da codice, ma, come dicevo, in generale, se non sono alla canna del gas :-) uso un mio Helper (una versione è disponibile sotto http://thinkmobile.it/files nella demo Sql 2005 Mobile Performance) che apre e chiude le connessioni.
      1. L'unica eccezione che uso per i comandi complessi è l'utilizzo di un comando Prepared (un esempio è sempre nella demo indicata in cui sono presente anche i tempi di accesso di tutti i metodi di accesso ai dati per una comparazione). In questo caso viene passato all'helper un parametro per non distruggere la connessione (in pratica non viene indicato il CommandBehavior.CloseConnection su DataReader) e una variabile statica per tenere vivo il comando preparato
    5. Ancora su SqlCeResultSet
      1. spesso una maschera che presenta una griglia apre una seconda maschera di dettaglio (una seconda griglia con il dettaglio ordini ad esempio o una maschera di editing della prima): con un resultset statico o key-driven ci sono dei lock sui record...cosa che  nessuno di noi vuole avere durante un'update o peggio ancora una Delete del record dalla maschera secondaria
      2. Se facciamo operazioni in background, come ad esempio una Merge Replication, che succede alla nostra griglia (o ai campi in bind sulla user interface) mentre vengono aggiornati i dati dietro le quinte ? Vero che potremmo usare un ResultSet non aggiornabile e non-sensitive (Insensitive per l'enum)...ma in questo caso perchè non usare un DataReader ?
      3. Il punto 2 precedente è opinabile perchè un DataReader non consente binding...vero...però è altrettanto vero che non dovremmo mai portare oggetti "database" (classi di accesso ai dati) sulla User Interface...altrimenti ci leghiamo all'implementazione specifica del DB e non possiamo cambiare database (e metodi di accesso ai dati nelle tecnologie a venire) se non sbaraccando tutto
    6. Sempre a proposito di connessioni potrebbe essere sensato avere due connection string in una applicazione: una per leggere i dati (Mode=Read Only) e una tradizionale per letture/scritture: in questo modo possiamo evitare SLock inutili. Se usiamo Mode=Read Only occorre impostare una path per il TempDB tramite l'attributo Temp File Path.
    7. A proposito di TempDB occhio che se crasha SQLCE il tempdb resta nella posizione: occorre cancellarlo da codice. Il TempDB viene usato anche per tutte le query che non possono sfruttare un indice....ma non ce ne dovrebbero essere...
    Posted: apr 21 2007, 03:10 by rob | with no comments |
    Filed under: