2010-10-25 22 views
10

Abbiamo circa 7-8 tabelle nella nostra applicazione Android aventi ciascuna circa 8 colonne in media. Entrambe le operazioni di lettura e scrittura vengono eseguite sul database e sto sperimentando e cercando di trovare modi per migliorare le prestazioni del livello DataAccess. Così, ora ho provato i seguenti:Ottimizzazione SQLite per l'applicazione Android

  1. Usare argomenti posizionali in cui le clausole (motivo: in modo che SQLite fa uso dello stesso piano di esecuzione)
  2. Racchiudere inserti e l'aggiornamento con le transazioni (Motivo: ogni operazione db è incluso in una transazione per impostazione predefinita.Questo rimuoverà l'overhead)
  3. Indicizzazione: non ho creato alcun indice esplicito diverso da quelli creati per impostazione predefinita sulla chiave primaria e sulle colonne di chiavi univoche. (Motivo: l'indicizzazione migliorerà il tempo di ricerca)

I have m ha preso in considerazione le mie ipotesi in parantesi; Perfavore, correggimi se sbaglio.

Domande:

  1. Posso aggiungere altro a questa lista? Ho letto da qualche parte che evitare l'uso di db-journal può migliorare le prestazioni degli aggiornamenti? È un mito o un fatto? Come può essere fatto, se consigliato?

  2. Le transazioni nidificate sono consentite in SQLite3? In che modo influenzano le prestazioni? Il problema è che ho una funzione che esegue un aggiornamento in un ciclo, quindi ho racchiuso il ciclo all'interno di un blocco di transazione. A volte questa funzione viene chiamata da un altro ciclo all'interno di un'altra funzione. La funzione chiamante racchiude anche il ciclo all'interno di un blocco di transazione. In che modo tale nidificazione delle transazioni influisce sulle prestazioni?

  3. Le clausole where delle mie query utilizzano più di una colonna per creare il predicato. Queste colonne potrebbero non necessariamente tramite una chiave primaria o colonne univoche. Dovrei creare indici anche su queste colonne? È una buona idea creare più indici per un tale tavolo?

risposta

12
  1. definire esattamente quali sono le ricerche è necessario ottimizzare. Prendi una copia di un tipico database e usa il REPL per le interrogazioni temporali. Utilizzalo per confrontare i guadagni mentre ottimizzi.

  2. Utilizzare ANALYZE per consentire al pianificatore di query di SQLite di funzionare in modo più efficiente.

  3. Per SELECT s e UPDATE s, gli indici possono fare le cose, ma solo se gli indici creati possono essere effettivamente utilizzati dalle query che è necessario accelerare.Utilizzare EXPLAIN QUERY PLAN per le query per vedere quale indice sarebbe utilizzato o se la query richiede una scansione completa della tabella. Per tabelle di grandi dimensioni, una scansione completa della tabella non è corretta e probabilmente si desidera un indice. Verrà utilizzato un solo indice su qualsiasi query. Se si dispone di più predicati, l'indice che verrà utilizzato è quello che si prevede di ridurre maggiormente il set di risultati (in base a ANALYZE). È possibile avere indici che contengono più colonne (per aiutare le query con più predicati). Se si hanno indici con più colonne, sono utilizzabili solo se i predicati adattano l'indice da sinistra a destra senza spazi vuoti (ma le colonne non utilizzate alla fine vanno bene). Se si utilizza un predicato di ordinamento (<, <=, > ecc.), È necessario che sia nell'ultima colonna utilizzata dell'indice. Utilizzando entrambi i predicati WHERE e ORDER BY entrambi richiedono un indice e SQLite ne può utilizzare solo uno, in modo che possa essere un punto in cui la prestazione soffre. Più indici hai, più lento sarà il tuo INSERT s, quindi dovrai calcolare il miglior compromesso per la tua situazione.

  4. Se si dispone di query più complesse che non possono utilizzare alcun indice che è possibile creare, è possibile de-normalizzare lo schema, strutturando i dati in modo che le query siano più semplici e si possa rispondere utilizzando indici.

  5. Se si sta eseguendo un gran numero di INSERT s, provare a eliminare gli indici e ricrearli alla fine. Dovrai confrontarlo con questo.

  6. SQLite does support nested transactions utilizzando i punti di salvataggio, ma non sono sicuro che si ottenga qualcosa in termini di prestazioni.

  7. È possibile gain lots of speed by compromising on data integrity. Se è possibile recuperare da corruzione del database te stesso, allora questo potrebbe funzionare per voi. Potresti forse farlo solo quando stai facendo operazioni intensive che puoi recuperare manualmente.

Non sono sicuro di quanto è possibile ottenere da un'applicazione Android. C'è un more detailed guide per l'ottimizzazione di SQLite in generale nella documentazione di SQLite.

+0

Grazie per aver dedicato del tempo per rispondere a questa domanda. – Samuh

1

Vorrei aggiungere questi:

  1. Utilizzando delle rawQuery() invece di costruire utilizzando contentValues ​​sarà fissare in certi casi. Ovviamente è un po 'noioso scrivere query non elaborate.

  2. Se si dispone di molti dati di tipo stringa/testo, è consigliabile creare tabelle virtuali utilizzando la ricerca testo completo (FTS3), che può eseguire query più veloci. puoi cercare su google gli esatti miglioramenti della velocità.

8

Ecco un po 'di codice per ottenere risultati EXPLAIN QUERY PLAN in logcat Android da un'app Android in esecuzione. Sto iniziando con uno SQLiteOpenHelper dbHelper e uno SQLiteQueryBuilder qb.

String sql = qb.buildQuery(projection,selection,selectionArgs,groupBy,having,sortOrder,limit); 
android.util.Log.d("EXPLAIN",sql + "; " + java.util.Arrays.toString(selectionArgs)); 
Cursor c = dbHelper.getReadableDatabase().rawQuery("EXPLAIN QUERY PLAN " + sql,selectionArgs); 
if(c.moveToFirst()) { 
    do { 
     StringBuilder sb = new StringBuilder(); 
     for(int i = 0; i < c.getColumnCount(); i++) { 
      sb.append(c.getColumnName(i)).append(":").append(c.getString(i)).append(", "); 
     } 
     android.util.Log.d("EXPLAIN",sb.toString()); 
    } while(c.moveToNext()); 
} 
c.close(); 

ho abbandonato questo nella mia ContentProvider.query() e ora posso vedere esattamente come sono sempre eseguite tutte le query. (Nel mio caso sembra che il problema è troppe domande piuttosto che cattivo utilizzo di indicizzazione, ma forse questo aiuterà qualcun altro ...)

0

Un piccolo punto di aggiungere alla risposta altrimenti completa di Robie: VFS in SQLite (che riguarda principalmente il blocco) può essere scambiato per alternative. È possibile trovare una delle alternative come unix-excl o unix-nessuno essere più veloce, ma attenzione gli avvisi sul SQLite VFS page!

Normalization (di strutture tabella) è anche la pena considerare (se non l'hai già) semplicemente perché tende a fornire la più piccola rappresentazione dei dati nel database; questo è un trade-off, meno I/O per più CPU, e uno che è di solito utile in database enterprise di media scala (il tipo che mi è più familiare), ma temo di non avere idea se il il trade-off funziona bene su piattaforme su piccola scala come Android.