Guida allo sviluppo

Local Navigation

Prestazioni del database SQLite

Rispetto ai computer, i dispositivi mobili offrono un ambiente molti limitato per i database SQLite. Per ottenere prestazioni ottimali su uno smartphone BlackBerry, tenere in considerazione i seguenti vincoli:

  • Il limite di memoria dinamico è pari a 16 MB. Questo limite fa riferimento alla quantità di RAM disponibile per la memorizzazione, da parte di un database SQLite, delle strutture di dati interne per gli schemi e le transazioni. Lo schema dell'intero database viene caricato nella memoria quando viene aperto un database SQLite e rimane nella memoria fin quando il database non viene chiuso.

  • La lunghezza massima della query SQL è di 1 MB.

  • Il numero massimo di database che è possibile aprire contemporaneamente è di circa 50. L'API Database utilizza una modalità cache condivisa, per consentire un utilizzo efficiente di memoria per le connessioni multiple allo stesso database.

  • È possibile eseguire una sola connessione in lettura/scrittura alla volta al database SQLite. Le altre connessioni database sono di sola lettura.

Quando si utilizzano i metodi Database.createBlobOutputStream e Database.createBlobInputStream per la lettura e scrittura dei BLOB, la memoria disponibile per SQLite non limita le dimensioni del BLOB che è possibile utilizzare: l'insieme di risultati non è limitato a 1 MB.

È possibile tenere traccia dell'utilizzo della memoria per ciascuna connessione al database tramite i seguenti metodi: Database.getCacheUsed, Database.getSchemaUsed e Database.getStatementUsed.

Descrizione di SQLite come servizio

Su uno smartphone BlackBerry, SQLite viene eseguito come servizio. Le operazioni di database utilizzano un collegamento runtime per il trasferimento dei dati tra Java e il codice nativo. Esiste un 1 limite di MB sulla quantità di dati che è possibile trasferire tramite il collegamento runtime. Il collegamento runtime può offrire prestazioni eccellenti riguardo alle operazioni di database, ma può ridurre le prestazioni se non viene utilizzato in modo appropriato.

Quando si crea un'istruzione preparata per l'inserimento o l'aggiornamento dei dati, è necessario utilizzare i metodi Statement.executeInsert o Statement.executeUpdate per ridurre il numero di chiamate tramite il collegamento runtime. Questi metodi consentono di eseguire le seguenti operazioni nel codice nativo:

  • Associare i parametri SQL
  • Eseguire l'istruzione
  • Reimpostare l'istruzione
  • Deselezionare le associazioni
  • Restituire l'ultimo ID della riga inserito ( solo executeInsert)

Quando si esegue una query che non restituisce un insieme di risultati e non vengono associati parametri, è necessario utilizzare il metodo Database.executeStatement, che riduce il numero di chiamate tramite il collegamento runtime, eseguendo le seguenti operazioni nel codice nativo:

  • Preparare l'istruzione
  • Eseguire l'istruzione
  • Finalizzare l'istruzione

Quando si esegue una query che restituisce insiemi di risultati tramite il metodo Statement.getCursor, è possibile recuperare preventivamente un determinato numero di righe, tramite il metodo Statement.setCursorBufferSize. Questo approccio consente di ridurre l'utilizzo del collegamento runtime. Quando il cursore si sposta oltre l'insieme di dati nel buffer, viene automaticamente recuperato un nuovo batch di righe. È possibile recuperare il numero di righe che un cursore memorizzerà nel buffer tramite il metodo Statement.getCursorBufferSize.

Quando si recuperano valori interi da utilizzare come chiavi in un'altra query, è possibile utilizzare i metodi Statement.getIntegers e Statement.getLongs. Questi metodi consentono di semplificare e ottimizzare il recupero delle colonne degli interi.

Procedura consigliata: ottimizzazione delle prestazioni di un database SQLite

Attenersi alle seguenti istruzioni:

Procedura consigliata Descrizione

Utilizzare la modalità del diario appropriata

Per impostazione predefinita, viene utilizzato un diario di ripristino per registrare le transazioni, ma è possibile scegliere di utilizzare invece un registro write-ahead. Il registro write-ahead aumenta la simultaneità delle operazioni e risulta più veloce del diario di ripristino nella maggior parte delle situazioni, poiché la scrittura sul database non blocca la lettura. Tuttavia, il registro write-ahead utilizza più handle di file. Il registro write-ahead utilizza fino a tre handle di file che possono rimanere memorizzati per lunghi periodi, mentre il diario di ripristino ne utilizza uno, o talvolta due, durante la scrittura delle transazioni. Per modificare la modalità del diario in un registro write-ahead, eseguire l'istruzione SQL "PRAGMA journal_mode = WAL;".

Provare a diminuire i vincoli di sicurezza per le tabelle

Quando l'integrità dei dati non rappresenta una priorità, provare ad utilizzare i comandi Pragma per evitare di specificare un diario e per disattivare la modalità sincrona. Ad esempio, PRAGMA journal_mode=OFF e PRAGMA synchronous=OFF.

Prova

Se si pensa di creare un database con uno schema di grandi dimensioni o di inserire BLOB di grandi dimensioni, è necessario eseguire il test del database sugli smartphone BlackBerry di destinazione, per assicurarsi che gli smartphone dispongano di una quantità di memoria sufficiente.

Archiviare il minor numero possibile di dati

La maggior parte del tempo di elaborazione dei database SQLite viene impiegata per la lettura e la scrittura per l'archiviazione. Un minor numero di dati significa in genere un minor numero di letture e scritture. Il motore di database SQLite memorizza nella cache le pagine del database a cui si accede frequentemente. Archiviando un numero di dati inferiore, è possibile aumentare la probabilità che il motore di database SQLite recuperi i dati richiesti più rapidamente dalla cache anziché dalla memoria relativamente lenta.

Raggruppare le istruzioni con transazioni esplicite

Se non si utilizzano transazioni esplicite, viene creata una transazione per ogni istruzione eseguita. Questo comportamento predefinito non è efficiente. Presuppone l'apertura, la riapertura, la scrittura e la chiusura del file journal per ogni istruzione. Con le transazioni esplicite, è possibile raggruppare le istruzioni per ottenere una maggiore efficienza. È possibile eseguire più istruzioni in una sola transazione posizionando Database.beginTransaction e Database.commitTransaction in un gruppo di istruzioni.

Creare degli indici efficienti

Gli indici possono ridurre di molto il tempo richiesto per effettuare una ricerca in una tabella. Di seguito, sono riportate alcune note sulla creazione di indici efficienti:

  • Gli indici possono migliorare le prestazioni per le query di sola lettura, come ad esempio SELECT, ma possono ridurre le prestazioni per le query che modificano le righe. Provare a indicizzare solo le tabelle che vengono aggiornate raramente.
  • L'ordine delle colonne in un indice influisce sulle prestazioni. Le colonne utilizzate in genere nelle clausole WHERE dovrebbero essere collocate per prime, seguite dalle colonne utilizzate in genere nelle clausole BY.
  • Per le colonne contenenti dati recuperati, creare un indice di copertura.
  • Evitare gli indici duplicati. Il motore di database SQLite crea automaticamente gli indici per le colonne che hanno i vincoli UNIQUE o PRIMARY KEY.
  • Le colonne denominate INTEGER PRIMARY KEY producono query più veloci perché hanno accesso diretto ai dati della tabella.

Ridurre la dimensione delle righe

Se si dispone di una colonna molto ampia, prendere in considerazione la possibilità di inserirla in una tabella separata.

Memorizzare appropriatamente i BLOB

Se i dati dell'utente includono BLOB, è necessario leggerli e scriverli tramite gli oggetti InputStream e OutputStream, utilizzando createBlobInputStream e createBlobOutputStream.

È anche possibile provare a memorizzare ciascun BLOB in una tabella separata. Se i BLOB sono molto grandi, è possibile memorizzarli come file all'esterno del database (e memorizzare il percorso per ogni file del database), ma questa procedura implica un sovraccarico per la ricerca dei nomi dei file.

Prendere in considerazione l'utilizzo delle tabelle temporanee

Se non è necessario rendere disponibili i dati dopo il riavvio dello smartphone, utilizzare l'istruzione CREATE TEMP TABLE invece di CREATE TABLE.

Utilizzare i parametri SQL

Per eseguire una serie di istruzioni dello stesso formato, preparare prima un'istruzione generica che utilizzi i parametri SQL. È possibile eseguire l'istruzione reiterando i valori variabili e associando i valori alle variabili denominate in ogni iterazione.

Non utilizzare delle sottoquery

In alcuni casi, il motore di database SQLite memorizza i risultati della sottoquery in un file temporaneo, che può rallentare l'elaborazione.

Deframmentare il database

Utilizzare il comando VACUUM di SQLite per deframmentare il database. Questo processo riduce anche la dimensione del file di database.

Nelle istruzioni per le tabelle, prendere in considerazione l'ordine delle colonne.

L'ordine delle colonne in una dichiarazione di tabella influisce sulle prestazioni, soprattutto in caso di assenza di un indice, perché il motore di database SQLite effettua una ricerca nelle colonne nell'ordine definito nella dichiarazione di tabella. Le colonne che contengono un minor numero di dati, ai quali si accede con frequenza, dovrebbero essere collocate prima delle colonne contenenti un maggior numero di dati, ai quali si accede raramente.

Utilizzare i metodi di funzionamento in blocco

I seguenti metodi di funzionamento in blocco consentono un utilizzo efficiente del collegamento runtime:

Per ulteriori informazioni, vedere Descrizione di SQLite come servizio.

Argomento successivo: Utilizzo dei database SQLite

Le informazioni sono state utili? Inviateci i vostri commenti.