Guía de desarrollo

Local Navigation

Rendimiento de las bases de datos SQLite

En comparación con los ordenadores, los dispositivos móviles ofrecen un entorno muy limitado para una base de datos SQLite. Para lograr el rendimiento óptimo en un smartphone BlackBerry, considere las siguientes limitaciones:

  • El límite de la memoria dinámica es de 16 MB. Este límite se refiere a la cantidad de RAM disponible de una base de datos SQLite para almacenar estructuras internas de datos para esquemas y transacciones. El esquema completo de la base de datos se carga en la memoria cuando una base de datos SQLite está abierta y persiste hasta que la base de datos se cierra.

  • La longitud máxima de la consulta SQL es de 1 MB.

  • El número máximo de bases de datos que pueden estar abiertas al mismo tiempo es de aproximadamente 50. La API de base de datos utiliza un modo de caché compartido para hacer un uso eficiente de la memoria para múltiples conexiones a la misma base de datos.

  • Sólo se puede realizar al mismo tiempo una conexión de base de datos de lectura y escritura con una base de datos SQLite. El resto de conexiones de bases de datos son de sólo lectura.

Cuando utilice los métodos Database.createBlobOutputStream y Database.createBlobInputStream para leer y escribir BLOB, la memoria disponible en SQLite no restringe el tamaño del BLOB que puede utilizar: el conjunto de resultados no está limitado a 1 MB.

Puede realizar un seguimiento del uso de la memoria en cada conexión de base de datos mediante los siguientes métodos: Database.getCacheUsed, Database.getSchemaUsed y Database.getStatementUsed.

Definición de SQLite como servicio

En un smartphone BlackBerry, SQLite se ejecuta como servicio. Las operaciones de la base de datos utilizan un tiempo de ejecución para transferir los datos entre Java y el código de origen. La cantidad de datos que se puede transferir durante el tiempo de ejecución tiene un límite de 1 MB. El tiempo de ejecución puede proporcionar un excelente rendimiento de las operaciones de la base de datos, pero también puede disminuir el rendimiento si no se utiliza correctamente.

Al crear una instrucción preparada para introducir o actualizar datos, debe utilizar los métodos Statement.executeInsert o Statement.executeUpdate para reducir el número de llamadas durante el tiempo de ejecución. Estos métodos realizan las siguientes operaciones en el código de origen:

  • Vinculan los parámetros de SQL
  • Ejecutan la instrucción
  • Restablecen la instrucción
  • Borran las vinculaciones
  • Restablecen el último ID de fila insertado (sólo executeInsert)

Al ejecutar una consulta que no devuelve un conjunto de resultados y que no está vinculando los parámetros, debe utilizar el método Database.executeStatement, que reduce el número de llamadas durante el tiempo de ejecución realizando las siguientes operaciones en el código de origen:

  • Preparan la instrucción
  • Ejecutan la instrucción
  • Completan la instrucción

Al ejecutar una consulta que devuelve un conjunto de resultados mediante el método Statement.getCursor, puede obtener un número especifico de filas mediante el método Statement.setCursorBufferSize. Este enfoque reduce el uso del tiempo de ejecución. Cuando el cursor deja atrás el conjunto almacenado en búfer, se obtiene automáticamente una serie de filas nueva. Puede recuperar el número de filas que almacenará el cursor en búfer mediante el método Statement.getCursorBufferSize.

Al recuperar los valores de números enteros para utilizarlos como claves en otra consulta, puede utilizar los métodos Statement.getIntegers y Statement.getLongs. Estos métodos simplifican y optimizan la recuperación de columnas de números enteros.

Práctica recomendada: optimización del rendimiento de la base de datos SQLite

Considere las siguientes directrices:

Práctica recomendada Descripción

Utilice el modo apropiado de diario

De forma predeterminada, un diario de recuperación se utiliza para registrar transacciones, pero puede decidir utilizar un registro de escritura anticipada en su lugar. El registro de escritura anticipada ofrece una concurrencia mejorada y es más rápido que el diario de recuperación en la mayoría de situaciones debido a que al escribir en la base de datos, la función de lectura también está activa. Sin embargo, el registro de escritura anticipada utiliza más identificadores de archivos. El registro de escritura anticipada utiliza hasta tres identificadores de archivos que pueden persistir durante largos periodos, mientras que el diario de recuperación utiliza uno, u ocasionalmente dos, durante las transacciones de escritura. Para cambiar del modo de diario al de registro de escritura anticipada, ejecute la instrucción SQL "PRAGMA journal_mode = WAL;".

Plantéese reducir las restricciones de seguridad en las tablas.

Cuando la integridad de los datos no sea un problema, considere utilizar los comandos Pragma para no especificar un diario y desactivar el modo sincrónico. Por ejemplo, PRAGMA journal_mode=OFF y PRAGMA synchronous=OFF.

Prueba

Si tiene previsto crear una base de datos con un esquema de gran tamaño o insertar BLOB de gran tamaño, debe probar la base de datos en el smartphone BlackBerry de destino para asegurarse de que cuenta con la memoria adecuada.

Almacenar el menor número de datos posible

La mayor parte del tiempo de procesamiento de las bases de datos SQLite se emplea en la lectura y escritura del almacenamiento. Menos datos implican generalmente menos procesos de lectura y escritura. El motor de la base de datos SQLite guarda en la caché las páginas de la base de datos a las que se accede con mayor frecuencia. Al almacenar menos datos, puede aumentar la probabilidad de que el motor de la base de datos SQLite recupere de forma más rápida los datos solicitados de la caché en vez de hacerlo del acceso relativamente lento al almacenamiento.

Agrupar las instrucciones con transacciones explícitas

Si no utiliza transacciones explícitas, se creará una transacción para cada instrucción que se ejecute. Este comportamiento predeterminado es ineficaz. Requiere que se abra, se vuelva abrir, se escriba y se cierre el archivo de diario para cada instrucción. Con transacciones explícitas, puede agrupar las instrucciones para obtener una mayor eficiencia. Puede ejecutar varias instrucciones en una transacción colocando Database.beginTransaction y Database.commitTransaction alrededor de un grupo de instrucciones.

Crear índices eficaces

Los índices pueden reducir en gran medida el tiempo necesario para analizar una tabla. Éstas son algunas notas acerca de cómo crear índices eficaces:

  • Los índices pueden mejorar el rendimiento de las consultas de sólo lectura como SELECT, pero también pueden reducir el rendimiento de las consultas que cambian las filas. Tenga en cuenta sólo las tablas de índice que no se actualizan con frecuencia.
  • El orden de las columnas en un índice afecta al rendimiento. Las columnas que se utilizan normalmente en cláusulas WHERE deben colocarse en primer lugar, seguidas de las columnas que se utilizan normalmente en las cláusulas ORDER BY.
  • Para las columnas que contienen los datos que se han recuperado, cree un índice "covering index".
  • Evite la creación de índices duplicados. El motor de la base de datos SQLite crea automáticamente los índices para las columnas que cuentan con las restricciones UNIQUE o PRIMARY KEY.
  • Las columnas declaradas como INTEGER PRIMARY KEY permiten realizar consultas más rápidas porque tienen acceso directo a los datos de la tabla.

Minimizar el tamaño de las filas

Si una de las columnas es muy ancha, considere ponerla en una tabla independiente.

Almacenar BLOB adecuadamente

Si los datos incluyen BLOB, debe leerlos y escribirlos utilizando los objetos InputStream y OutputStream mediante createBlobInputStream y createBlobOutputStream.

También puede considerar almacenar cada BLOB en una tabla independiente. Si los BLOB son de gran tamaño, podrá almacenarlos como archivos fuera de la base de datos (y almacenar la ruta de cada archivo en la base de datos), pero esta práctica genera una sobrecarga para las búsquedas por nombre de archivo.

Considerar el uso de tablas temporales

Si no necesita que los datos sigan estando disponibles después del reinicio del smartphone, utilice la instrucción CREATE TEMP TABLE en lugar de CREATE TABLE.

Utilizar parámetros de SQL

Para ejecutar un conjunto de instrucciones del mismo formato, prepare en primer lugar una instrucción genérica que utilice parámetros de SQL. Puede ejecutar las instrucciones mediante la iteración de los valores de variable y la vinculación de los valores a las variables con nombre en cada iteración.

Evitar las subconsultas

En ocasiones, el motor de la base de datos SQLite almacena los resultados de la subconsulta en un archivo temporal, que puede ralentizar el procesamiento.

Desfragmentar la base de datos

Utilice el comando VACUUM de SQLite para desfragmentar la base de datos. Este proceso también reduce el tamaño del archivo de la base de datos.

Considerar el orden de las columnas en las declaraciones de tabla

El orden de las columnas en una declaración de tabla afecta al rendimiento, especialmente en ausencia de un índice, porque el motor de la base de datos SQLite analiza las columnas en el orden definido en la declaración de tabla. Las columnas que contienen pequeñas cantidades de los datos a los que se accede con más frecuencia deben colocarse delante de las columnas que contiene una gran cantidad de los datos a los que se accede con escasa frecuencia.

Utilizar métodos de operaciones masivas

Los métodos de operaciones masivas siguientes hacen un uso eficiente del tiempo de ejecución:

Para obtener más información, consulte Definición de SQLite como servicio.


¿Le ha resultado útil esta información? Envíenos sus comentarios.