2012-01-04 16 views
5

Sto usando SQLite nella mia app iOS e ho un sacco di risparmio/caricamento da fare mentre l'utente sta interagendo con l'interfaccia utente. Questo è un problema in quanto rende l'interfaccia utente molto nervosa e lenta.iOS SQLite Slow Performance

Ho provato a eseguire le operazioni in un thread aggiuntivo ma non penso sia possibile in SQLite. Ottengo frequentemente i codici di errore SQLITE_BUSY e SQLITE_LOCKED se lo faccio.

C'è un modo per farlo nel multithreading senza quei codici di errore, o dovrei abbandonare SQLite?

+1

Hai provato a sintonizzare le query che usi e guardando i piani di query per vedere se sono necessari degli indici? –

+2

Stai usando le transazioni quando fai più scritture? Dovresti - fa un'enorme differenza. –

+0

Frederick Cheung: sto usando più di una scrittura e un recupero. Cercherò di vedere se l'indicizzazione sarà d'aiuto, ma ci sono molti record da inserire quindi non credo che l'indicizzazione possa essere d'aiuto. Hot Licks: non sto effettuando transazioni quando si utilizzano più scritture. Dovrei farlo per ogni scrittura nel database usando lo stesso lock? – VTS12

risposta

0

Non abbandonare SQLite. Puoi sicuramente farlo in una discussione diversa dalla filettatura UI per evitare lentezza. Assicurati solo che il thread di uno acceda al database alla volta. SQLite non è eccezionale quando si ha a che fare con un accesso concorrente.

+1

Va bene per _reads_ simultanei, ma _updates_ blocca tutto il resto (a causa della complessità di qualcosa di più fine di un blocco a livello di DB). –

+0

Il mio problema è che non riesco a controllare quando l'utente accede/scrive dati. Ad esempio, in una vista legge e salva i dati, ma poi possono fare clic sui dettagli e premere una nuova vista che vorrà anche leggere/scrivere i dati. Non sono sicuro di come posso essere sicuro che un thread acceda al database nello stesso momento. – VTS12

3

È perfettamente possibile, è sufficiente serializzare l'accesso a SQLite nel thread in background.

La mia risposta su this recent question dovrebbe indicare la direzione giusta.

Come accennato altrove, SQLite va bene per letture contemporanee, ma si blocca a livello di database per le scritture. Ciò significa che se stai leggendo e scrivendo in thread diversi, riceverai errori SQLITE_BUSY e SQLITE_LOCKED.

Il modo più semplice per evitare questo è di puntate tutti accesso DB (letture e scritture) o in una coda spedizione o un NSOperationQueue che ha una concorrenza di 1. Poiché questo accesso non sta avvenendo sul thread principale , l'interfaccia utente non sarà interessata.

Questo ovviamente interromperà le letture e le scritture che si sovrappongono, ma fermerà anche le letture simultanee. Non è chiaro se si tratti di un successo nelle prestazioni che puoi prendere o meno.

per inizializzare una coda come descritto in precedenza:

NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init]; 

[backgroundQueue setMaxConcurrentOperationCount:1]; 

Poi si può semplicemente aggiungere operazioni alla coda, come si vede in forma.

+0

Ho provato a farlo in questo modo e ho ancora riscontrato errori. Ora sto utilizzando una coda di invio. – VTS12

+0

, ora tutto funziona correttamente? Anche una coda di spedizione dovrebbe andare bene. – paulbailey

+0

No, dopo aver utilizzato una coda di invio ottengo costantemente i codici di errore SQLITE_BUSY e SQLITE_LOCKED. Anche il comportamento strano come le visualizzazioni vengono saltate in anticipo, ecc. – VTS12

0

OFF:

Avere si checkout: FMDB si tratta di un wrapper SQLite ed è thread-safe. L'ho usato in tutto il mio progetto sqlite.

2

Avere tutto in un thread SQLite dedicato o una coda di operazioni one-op-at-a-time sono ottime soluzioni, soprattutto per risolvere l'interfaccia utente nervosa. Un'altra tecnica (che potrebbe non aiutare i nervosismi) è quella di individuare quei codici di errore, e semplicemente il ciclo, riprovare l'aggiornamento fino a ottenere un codice di ritorno corretto.

1

Inserire SQLite in modalità WAL. Quindi le letture non saranno bloccate. Non così scrive: è necessario serializzarli. Ci sono vari modi su come raggiungerlo. Uno di questi è offerto da SQLite. L'hook WAL può essere utilizzato per segnalare che può iniziare la scrittura successiva.

La modalità WAL dovrebbe generalmente migliorare le prestazioni della tua app. La maggior parte delle cose sarà un po 'più veloce. Le letture non saranno bloccate affatto. Solo le transazioni di grandi dimensioni (diversi MB) rallenteranno. Generalmente niente di drammatico.