Avvertenza: potrebbero essere presenti inesattezze di seguito. Ho imparato molte cose mentre vado avanti, quindi prendilo con un pizzico di sale. Questo è piuttosto lungo, ma potresti semplicemente leggere i parametri con cui stavamo giocando, quindi saltare alla conclusione alla fine.
Esistono diversi livelli in cui puoi preoccuparti delle prestazioni di scrittura di SQLite:
Abbiamo esaminato quelli evidenziati in grassetto. I parametri particolari erano
- Cache di scrittura su disco. I dischi moderni hanno cache RAM che viene utilizzata per ottimizzare le scritture del disco rispetto al disco rotante. Con questa opzione abilitata, i dati possono essere scritti in blocchi fuori ordine, quindi se si verifica un arresto anomalo, si può finire con un file parzialmente scritto. Controllare l'impostazione con hdparm -W / dev / ... e impostarla con hdparm -W1 / dev / ... (per accenderlo e -W0 per spegnerlo).
- Barriera = (0 | 1). Molti commenti online che dicono "se corri con barrier = 0, allora non hai abilitato la cache di scrittura su disco". Puoi trovare una discussione sugli ostacoli su http://lwn.net/Articles/283161/
- data = (journal | ordinato | writeback). Guarda http://www.linuxtopia.org/HowToGuides/ext3JournalingFilesystem.html per una descrizione di queste opzioni.
- commit = N. Indica a ext3 di sincronizzare tutti i dati e i metadati ogni N secondi (impostazione predefinita 5).
- Pragma SQLite sincrono = ON | OFF. Se impostato su ON, SQLite assicurerà che una transazione sia "scritta su disco" prima di continuare. La disattivazione in sostanza rende le altre impostazioni in gran parte irrilevanti.
- Pragma SQLite cache_size. Controlla la quantità di memoria che SQLite utilizzerà per la sua cache in memoria. Ho provato due dimensioni: una in cui l'intero DB si adattava alla cache e una in cui la cache era la metà della dimensione massima del DB.
Maggiori informazioni sulle opzioni ext3 nella documentazione ext3 .
Ho eseguito test delle prestazioni su una serie di combinazioni di questi parametri. L'ID è un numero di scenario, indicato di seguito.
Ho iniziato eseguendo con la configurazione predefinita sulla mia macchina come scenario 1. Lo scenario 2 è quello che presumo sia il "più sicuro", quindi ho provato varie combinazioni, ove appropriato / richiesto. Questo è probabilmente il più facile da capire con la mappa che ho finito per usare:
Ho scritto uno script di test che ha eseguito molte transazioni, con inserimenti, aggiornamenti ed eliminazioni, tutte su tabelle con solo INTEGER, solo TEXT (con colonna ID) o miste. L'ho eseguito diverse volte su ciascuna delle configurazioni sopra:
I due scenari inferiori sono # 6 e # 17, che hanno "pragma synchronous = off", talmente sorprendente che erano i più veloci. Il prossimo gruppo di tre sono # 7, # 11 e # 19. Questi tre sono evidenziati in blu sulla "mappa di configurazione" sopra. Fondamentalmente la configurazione è cache di scrittura su disco, barriera = 0 e dati impostati su qualcosa di diverso da 'journal'. La modifica del commit tra 5 secondi (n. 7) e 60 secondi (n. 11) sembra fare poca differenza. In questi test non sembrava esserci molta differenza tra data = ordinato e data = writeback, il che mi ha sorpreso.
Il test di aggiornamento misto è il picco medio. Esiste un gruppo di scenari che sono più chiaramente più lenti in questo test. Questi sono tutti quelli con data = journal . Altrimenti non c'è molto tra gli altri scenari.
Ho fatto un altro test di temporizzazione, che ha fatto un mix più eterogeneo di inserti, aggiornamenti ed eliminazioni sulle diverse combinazioni di tipi. Questi hanno richiesto molto più tempo, motivo per cui non l'ho incluso nella trama sopra:
Qui puoi vedere che la configurazione del writeback (# 19) è un po 'più lenta di quella ordinata (# 7 e # 11). Mi aspettavo che il writeback fosse leggermente più veloce, ma forse dipende dai tuoi schemi di scrittura, o forse non ho ancora letto abbastanza su ext3 :-)
I vari scenari erano in qualche modo rappresentativi delle operazioni eseguite dalla nostra applicazione. Dopo aver selezionato un elenco di scenari, abbiamo eseguito test di temporizzazione con alcune delle nostre suite di test automatizzate. Erano in linea con i risultati di cui sopra.
Conclusione
- Il parametro commit sembrava fare poca differenza, quindi lo stiamo lasciando a 5 secondi.
- Andiamo con la cache di scrittura su disco attivata, barriera = 0 e dati = ordinati . Ho letto alcune cose online che pensavano che si trattasse di una configurazione errata e altre che sembravano pensare che questo dovesse essere il default in molte situazioni. Immagino che la cosa più importante sia che tu prenda una decisione informata, sapendo quali compromessi stai facendo.
- Non useremo il pragma sincrono in SQLite.
- L'impostazione del pragma cache_size di SQLite in modo che il DB si adattasse alla memoria ha migliorato le prestazioni in alcune operazioni, come previsto.
- La configurazione sopra indica che stiamo assumendo un rischio leggermente maggiore. Saremo utilizzando l' API di backup SQLite per ridurre al minimo il pericolo di guasto del disco su una scrittura parziale: uno snapshot ogni N minuti, e mantenendo l'ultimo M in giro. Ho testato questa API durante l'esecuzione dei test delle prestazioni e ci ha dato la sicurezza di procedere in questo modo.
- Se volessimo ancora di più, potremmo guardare al caos con il kernel, ma abbiamo migliorato abbastanza le cose senza andare lì.
Grazie a @Huygens per vari suggerimenti e consigli.