Malo rendimiento de SQLite en almacenamiento externo en Android

Estoy utilizando el almacenamiento externo para almacenar eventos en una base de datos mientras están esperando para ser enviados al servidor.

Estoy viendo realmente mal rendimiento al insertar registros. Sé que la memoria externa puede ser lenta, pero quería ver algunos números, así que escribí una pequeña aplicación que las pruebas.

Aquí está el código:

public static final int INSERTS = 100; File dbFile = new File(Environment.getExternalStorageDirectory(), "test.sqlite3"); // File dbFile = new File(getFilesDir(), "test.sqlite3"); dbFile.delete(); SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, null); db.execSQL("CREATE TABLE events (_id integer primary key autoincrement, event_type TEXT NOT NULL, timestamp BIGINT, data TEXT);"); db.execSQL("CREATE INDEX mainIndex ON events (event_type, timestamp ASC);"); InsertHelper helper = new InsertHelper(db, "events"); final int eventTypeCol = helper.getColumnIndex("event_type"); final int timestampCol = helper.getColumnIndex("timestamp"); final int dataCol = helper.getColumnIndex("data"); long start = System.currentTimeMillis(); String eventType = "foo", data = "bar"; long timestamp = 4711; for(int i = 0; i < INSERTS; ++i) { helper.prepareForInsert(); helper.bind(eventTypeCol, eventType); helper.bind(timestampCol, timestamp); helper.bind(dataCol, data); helper.execute(); } long end = System.currentTimeMillis(); Log.i("Test", String.format("InsertHelper, Speed: %d ms, Records per second: %.2f", (int)(end-start), 1000*(double)INSERTS/(double)(end-start))); db.close(); dbFile.delete(); db = SQLiteDatabase.openOrCreateDatabase(dbFile, null); db.execSQL("CREATE TABLE events (_id integer primary key autoincrement, event_type TEXT NOT NULL, timestamp BIGINT, data TEXT);"); db.execSQL("CREATE INDEX mainIndex ON events (event_type, timestamp ASC);"); start = System.currentTimeMillis(); ContentValues cv = new ContentValues(); for(int i = 0; i < INSERTS; ++i) { cv.put("event_type", eventType); cv.put("timestamp", timestamp); cv.put("data", data); db.insert("events", null, cv); } end = System.currentTimeMillis(); Log.i("Test", String.format("Normal, Speed: %d ms, Records per second: %.2f", end-start, 1000*(double)INSERTS/(double)(end-start))); db.close(); dbFile.delete(); 

La base de datos es exactamente como el que mi aplicación real está utilizando, he intentado eliminar el índice, pero no hizo ninguna diferencia.

Aquí están los resultados:

 Nexus One, Memoria interna

       Método |  Registros |  Tiempo (ms) |  Registros por segundo
 Unesdoc.unesco.org unesdoc.unesco.org ------
       Normal |  100 |  2072 |  48,26
 InsertHelper |  100 |  1662 |  60,17


 Nexus One, Memoria externa:

       Método |  Registros |  Tiempo (ms) |  Registros por segundo
 Unesdoc.unesco.org unesdoc.unesco.org ------
       Normal |  100 |  7390 |  13,53
 InsertHelper |  100 |  7152 |  13,98


 Emulador, Memoria interna:

       Método |  Registros |  Tiempo (ms) |  Registros por segundo
 Unesdoc.unesco.org unesdoc.unesco.org ------
       Normal |  100 |  1803 |  55,46
 InsertHelper |  100 |  3075 |  32,52


 Emulador, Memoria externa:

       Método |  Registros |  Tiempo (ms) |  Registros por segundo
 Unesdoc.unesco.org unesdoc.unesco.org ------
       Normal |  100 |  5742 |  17,42
 InsertHelper |  100 |  7164 |  13,96 

Como se puede ver el emulador no se puede confiar, InsertHelper debería ser más rápido si algo.
Esto es, por supuesto, que cabe esperar, la prueba se realizó sobre todo por curiosidad.

Lo que me preocupa sin embargo es el mal desempeño en mi teléfono cuando se utiliza la memoria externa, he perdido algún aspecto crucial de SQLiteDatabase o es simplemente para que la tarjeta SD será lento?

Puedo añadir que en mi aplicación real he desactivado el bloqueo y hace poca diferencia.

CommonsWare es correcto en su comentario. Algo que hace una gran diferencia para el rendimiento de db es el uso de transacciones. Envuelva su bucle de inserción en una transacción. No estoy 100% seguro si trabajaría con el InsertHelper pero usted puede intentar substituir su para el lazo con esto:

 db.beginTransaction(); try { for(int i = 0; i < INSERTS; ++i) { helper.prepareForInsert(); helper.bind(eventTypeCol, eventType); helper.bind(timestampCol, timestamp); helper.bind(dataCol, data); helper.execute(); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } 

Tengo algunos problemas de rendimiento db por lo que utiliza su código para medir los insertos por segundo en mi sistema. Pero también agregué wrapping en {begin, end} Transaction ().

En el emulador. Tengo:

 InsertHelper-Internal-Trans, Speed: 67 ms, Records per second: 1492.54 InsertHelper-External-Trans, Speed: 70 ms, Records per second: 1428.57 Normal-Internal-Trans, Speed: 148 ms, Records per second: 675.68 Normal-External-Trans, Speed: 152 ms, Records per second: 657.89 InsertHelper-Internal-NoTrans, Speed: 514 ms, Records per second: 194.55 Normal-Internal-NoTrans, Speed: 519 ms, Records per second: 192.68 InsertHelper-External-NoTrans, Speed: 590 ms, Records per second: 169.49 Normal-External-NoTrans, Speed: 618 ms, Records per second: 161.81 

Y en un Samsung Galaxy Nota:

 InsertHelper-External-Trans, Speed: 52 ms, Records per second: 1923.08 InsertHelper-Internal-Trans, Speed: 52 ms, Records per second: 1923.08 Normal-External-Trans, Speed: 77 ms, Records per second: 1298.70 Normal-Internal-Trans, Speed: 121 ms, Records per second: 826.45 Normal-External-NoTrans, Speed: 4562 ms, Records per second: 21.92 Normal-Internal-NoTrans, Speed: 4855 ms, Records per second: 20.60 InsertHelper-External-NoTrans, Speed: 5997 ms, Records per second: 16.68 InsertHelper-Internal-NoTrans, Speed: 8361 ms, Records per second: 11.96 
  • Limitación del número de filas en SQLite
  • Cómo obtener nombres de columna con datos de consulta en sqlite3?
  • Error de "Error al abrir la base de datos" al copiar una base de datos sqlite de activos En Android 4.2
  • La base de datos Sqlite debe crearse una sola vez
  • Eliminar varias filas de contentprovider
  • Compartir base de datos sqlite entre varias actividades de Android
  • Las teclas de cursor no funcionan cuando se utiliza sqlite3 desde el shell de adb
  • Problemas de Sqlite con HTC Desire HD
  • Recuperación del valor nulo de la base de datos Sqlite en android
  • Android sqlite3_limit?
  • La base de datos SQLite de Android está bloqueada
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.