studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones android performance memcached architecture design-guidelines

para - manual de programacion android pdf



La mejor práctica para mantener los datos en la memoria y la base de datos al mismo tiempo en Android (2)

Estamos diseñando una aplicación de Android que tiene muchos datos ("clientes", "productos", "pedidos" ...), y no queremos consultar SQLite cada vez que necesitamos algún registro. Queremos evitar consultar la base de datos lo más que podamos, así que decidimos mantener ciertos datos siempre en la memoria.

Nuestra idea inicial es crear dos clases simples:

  1. "MemoryRecord": una clase que contendrá básicamente una matriz de objetos (string, int, double, datetime, etc ...), que son los datos de un registro de tabla, y todos los métodos para obtener esos datos dentro / fuera de este formación.

  2. "MemoryTable": una clase que contendrá básicamente un Mapa de [Key, MemoryRecord] y todos los métodos para manipular este Mapa e insertar / actualizar / eliminar registros en / desde la base de datos.

Esas clases se derivarán para cada tipo de tabla que tenemos en la base de datos. Por supuesto, hay otros métodos útiles que no se encuentran en la lista anterior, pero no son importantes en este momento.

Entonces, cuando iniciemos la aplicación, cargaremos esas tablas desde una base de datos SQLite a la memoria usando esas clases, y cada vez que necesitemos cambiar algunos datos, cambiaremos en la memoria y lo publicaremos en la base de datos inmediatamente después.

Pero, queremos un poco de ayuda / consejo de usted. ¿Puede sugerir algo más simple o eficiente para implementar tal cosa? ¿O tal vez algunas clases existentes que ya lo hacen por nosotros?

Entiendo lo que ustedes están tratando de mostrarme, y les agradezco por eso.

Pero, digamos que tenemos una tabla con 2000 registros, y tendré que enumerar esos registros. Para cada uno, tengo que consultar otras 30 tablas (algunas de ellas con 1000 registros, otras con 10 registros) para agregar información adicional en la lista, y esto mientras está "volando" (y como saben, debemos ser muy rápidos en este momento).

Ahora vas a decir: "solo construye tu consulta principal con todas esas ''uniones'' y trae todo lo que necesitas en un solo paso. SQLite puede ser muy rápido, si tu base de datos está bien diseñada, etc. ...".

OK, pero esta consulta será muy complicada y segura, aunque SQLite es muy rápido, será "demasiado" lento (2 a 4 segundos, como confirmé, y este no es un tiempo aceptable para nosotros).

Otro factor complicado es que, dependiendo de la interacción del usuario, necesitamos "volver a consultar" todos los registros, porque las tablas involucradas no son las mismas, y tenemos que "volver a unirnos" con otro conjunto de tablas.

Entonces, una alternativa es traer solo los registros principales (esto nunca cambiará, sin importar lo que el usuario haga o quiera) sin unirse (¡esto es muy rápido!) Y consultar las otras tablas cada vez que queramos algunos datos. Tenga en cuenta que en la tabla con 10 registros solamente, buscaremos los mismos registros muchas veces. En este caso, es una pérdida de tiempo, porque no importa lo rápido que sea SQLite, siempre será más costoso realizar consultas, cursor, buscar, etc ... que simplemente tomar el registro de una especie de "memoria caché". Quiero dejar en claro que no planeamos mantener todos los datos en la memoria siempre, solo algunas tablas que consultamos muy a menudo.

Y llegamos a la pregunta original: ¿Cuál es la mejor manera de "almacenar en caché" esos registros? Realmente me gusta enfocar la discusión en eso y no "¿por qué necesitas almacenar datos en caché?"


El problema con una memoria caché es, por supuesto, que necesita mantenerlo sincronizado con la base de datos. Descubrí que consultar la base de datos es bastante rápido, y es posible que esté optimizando previamente aquí. He realizado muchas pruebas de consultas con diferentes conjuntos de datos y nunca demoran más de 10-20 ms.

Todo depende de cómo uses los datos, por supuesto. Los ListViews están bastante bien optimizados para manejar grandes cantidades de filas (he probado en el rango de 5000 sin problemas reales).

Si va a quedarse con el caché de memoria, es posible que desee que la base de datos notifique el caché cuando cambie el contenido y luego puede actualizar el caché. De esta forma, cualquier persona puede actualizar la base de datos sin saber sobre el almacenamiento en caché. Además, si crea un ContentProvider en su base de datos, puede usar ContentResolver para notificarle de cambios si se registra utilizando registerContentObserver.


La gran mayoría de las aplicaciones en la plataforma (contactos, correo electrónico, Gmail, calendario, etc.) no hacen esto. Algunos de estos tienen esquemas de bases de datos extremadamente complicados con potencialmente una gran cantidad de datos y no necesitan hacer esto. Lo que está proponiendo hacer le causará un gran dolor, sin una ganancia clara.

Primero debe concentrarse en diseñar su base de datos y su esquema para poder hacer consultas eficientes. Hay dos razones principales por las que puedo pensar para que el acceso a la base de datos sea lento:

  • Usted realmente ha complicado los esquemas de datos.
  • Tienes una gran cantidad de datos.

Si va a tener una gran cantidad de datos, no puede permitirse mantener todo en la memoria de todos modos, así que este es un callejón sin salida. Si tiene estructuras complicadas, se beneficiaría en cualquier caso con optimizarlas para mejorar el rendimiento. En ambos casos, su esquema de base de datos será clave para un buen rendimiento.

En realidad, optimizar el esquema puede ser algo así como un arte negro (y no soy un experto en él), pero algunas cosas a tener en cuenta son la creación correcta de índices en las filas que consultarás, diseñando combinaciones para que tomen caminos eficientes, etc. Estoy seguro de que hay muchas personas que pueden ayudarlo en esta área.

También puede intentar buscar en el origen de algunas de las bases de datos de la plataforma para obtener algunas ideas sobre cómo diseñar para obtener un buen rendimiento. Por ejemplo, la base de datos de contactos (especialmente a partir de 2.0) es extremadamente complicada y tiene muchas optimizaciones para proporcionar un buen rendimiento en datos relativamente grandes y conjuntos de datos extensibles con muchos tipos diferentes de consultas.

Actualizar:

Aquí hay una buena ilustración de lo importante que es la optimización de la base de datos. En la base de datos de proveedores de medios de Android, una versión más nueva de la plataforma cambió el esquema significativamente para agregar algunas características nuevas. El código de actualización para modificar una base de datos multimedia existente al nuevo esquema podría tardar 8 minutos o más en ejecutarse.

Un ingeniero realizó una optimización que redujo el tiempo de actualización de una base de datos de prueba real de 8 minutos a 8 segundos. Una mejora de rendimiento 60x.

¿Cuál fue esta optimización?

Fue para crear un índice temporal, en el momento de la actualización, en una columna importante utilizada en las operaciones de actualización. (Y luego elimínelo cuando haya terminado). Por lo tanto, esta mejora de rendimiento de 60x se produce a pesar de que también incluye el tiempo necesario para crear un índice en una de las columnas utilizadas durante la actualización.

SQLite es una de esas cosas en las que, si sabes lo que estás haciendo, puede ser notablemente eficiente. Y si no se cuida de cómo lo usa, puede terminar con un rendimiento miserable. Sin embargo, es una apuesta segura si tiene problemas de rendimiento y puede solucionarlos mejorando la forma en que usa SQLite.