2012-01-04 10 views
5

Estoy usando SQLite en mi aplicación iOS y tengo mucho que hacer/ahorrar mientras el usuario está interactuando con la interfaz de usuario. Esto es un problema ya que hace que la IU se ponga muy nerviosa y lenta.iOS SQLite Slow Performance

He intentado hacer las operaciones en un hilo adicional, pero no creo que esto sea posible en SQLite. Obtengo los códigos de error SQLITE_BUSY y SQLITE_LOCKED con frecuencia si hago eso.

¿Hay alguna manera de hacer esto en multiprocesamiento sin esos códigos de error, o debería abandonar SQLite?

+1

¿Has probado afinando las consultas que usas y mirando los planes de consulta para ver si se necesitan índices? –

+2

¿Está utilizando transacciones cuando realiza varias escrituras? Deberías - hace una gran diferencia. –

+0

Frederick Cheung: estoy usando múltiples escrituras y recuperaciones. Analizaré si la indexación ayudará, pero hay muchos registros que insertar, por lo que no creo que la indexación sea útil. Hot Licks: no estoy haciendo transacciones cuando uso múltiples escrituras. ¿Debo hacer esto para cada escritura en la base de datos usando el mismo candado? – VTS12

Respuesta

0

No abandone SQLite. Definitivamente puede hacerlo en un hilo diferente al UI hilo para evitar la lentitud. Solo asegúrese de que solo un hilo esté accediendo a la base de datos a la vez. SQLite no es genial cuando se trata de acceso concurrente.

+1

Está bien para _reads_ concurrentes, pero _updates_ bloquea todo lo demás (debido a la complejidad de cualquier cosa más detallada que el bloqueo de nivel de base de datos). –

+0

Mi problema es que no puedo controlar cuándo el usuario accede o escribe datos. Por ejemplo, en una vista, leerá y guardará los datos, pero luego podría hacer clic en los detalles e insertar una nueva vista que también querrá leer/escribir datos. No estoy seguro de cómo puedo asegurarme de que un hilo accede a la base de datos al mismo tiempo. – VTS12

3

Es perfectamente posible, solo necesita serializar el acceso a SQLite en su hilo de fondo.

Mi respuesta en this recent question debe apuntarle en la dirección correcta, creo.

Como se mencionó en otra parte, SQLite está bien para lecturas concurrentes, pero se bloquea en el nivel de base de datos para escrituras. Eso significa que si estás leyendo y escribiendo en diferentes subprocesos, obtendrás SQLITE_BUSY y SQLITE_LOCKED errors.

La forma más sencilla de evitar esto es serializar todo acceso DB (lectura y escritura), ya sea en una cola de distribución o un NSOperationQueue que tiene una concurrencia de 1. Como este acceso no está teniendo lugar en el hilo principal , su UI no se verá afectada.

Esto obviamente detendrá las lecturas y escrituras superpuestas, pero también detendrá las lecturas simultáneas. No está claro si se trata de un golpe de rendimiento que puede tomar o no.

para inicializar una cola como se describió anteriormente:

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

[backgroundQueue setMaxConcurrentOperationCount:1]; 

continuación, sólo puede añadir a la cola de operaciones como mejor le parezca.

+0

Intenté hacerlo de esta manera y aún experimenté errores. Ahora estoy usando una cola de despacho. – VTS12

+0

¿Ahora tiene todo funcionando correctamente entonces? Una cola de despacho también debería estar bien. – paulbailey

+0

No, después de usar una cola de despacho recibo constantemente los códigos de error SQLITE_BUSY y SQLITE_LOCKED. También el comportamiento extraño como las vistas se están revelando temprano, etc. – VTS12

0

OFF:

Tiene usted la comprobación: FMDB es un envoltorio de SQLite y es seguro para subprocesos. Lo usé en todo mi proyecto sqlite.

0

Recomiendo usar Core Data que se encuentra en la parte superior de sqlite. Lo uso en un entorno multiproceso. Aquí hay una guía en Concurrency with Core Data.

2

Tener todo en un hilo de SQLite dedicado, o una cola de operación de una sola vez son excelentes soluciones, especialmente para resolver su interfaz de usuario nerviosa. Otra técnica (que puede no ayudar a los nervios) es detectar esos códigos de error, y simplemente repetir el ciclo, reintentando la actualización hasta que obtenga un código de retorno exitoso.

1

Ponga SQLite en modo WAL. Entonces las lecturas no serán bloqueadas. No lo escribe, debe serializarlos. Hay varias formas de lograrlo. Uno de ellos es ofrecido por SQLite. El gancho WAL se puede usar para indicar que la próxima escritura puede comenzar.

El modo WAL generalmente debería mejorar el rendimiento de su aplicación. La mayoría de las cosas serán un poco más rápidas. Las lecturas no se bloquearán en absoluto. Solo las transacciones grandes (varios MB) se ralentizarán. Generalmente nada dramático.