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 
  • Cómo escribir una base de datos en un archivo de texto en android
  • Android sqlite3_limit?
  • Cómo utilizar un script para consultar la base de datos android sqlite
  • ¿Cómo obtener un cursor con valores distintos solamente?
  • Android SQLite ON CONFLICT UPDATE es posible?
  • Android - Código de error 11 al importar la base de datos Sqlite en Galaxy Note
  • Sqlite3 tabla con límite máximo de líneas (por elección) eficiencia
  • Orden de inserción de SQLite vs orden de consulta?
  • Obtención de base de datos SQLite por adb shell en cmd
  • Rowid en SQLite3 y Android
  • Pregunta de Android SQlite OnUpgrade
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.