Estoy usando el almacenamiento externo para almacenar eventos en una base de datos mientras esperan ser enviados al servidor.Mal rendimiento de SQLite en almacenamiento externo en Android
Estoy viendo un rendimiento muy malo al insertar registros. Sé que la memoria externa puede ser lenta, pero quería ver un número así que escribí una pequeña aplicación que lo prueba.
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 la que mi verdadera aplicación está utilizando, que intentó eliminar el índice, pero no había ninguna diferencia.
Éstos son los resultados:
Nexus One, Internal memory Method | Records | Time (ms) | Records per second -------------+---------+-----------+-------------------- Normal | 100 | 2072 | 48.26 InsertHelper | 100 | 1662 | 60.17 Nexus One, External memory: Method | Records | Time (ms) | Records per second -------------+---------+-----------+-------------------- Normal | 100 | 7390 | 13.53 InsertHelper | 100 | 7152 | 13.98 Emulator, Internal memory: Method | Records | Time (ms) | Records per second -------------+---------+-----------+-------------------- Normal | 100 | 1803 | 55.46 InsertHelper | 100 | 3075 | 32.52 Emulator, External memory: Method | Records | Time (ms) | Records per second -------------+---------+-----------+-------------------- 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 cabe.
Esto es, por supuesto, de esperar, la prueba se realizó principalmente por curiosidad.
Lo que me preocupa, sin embargo, es el mal funcionamiento en mi teléfono cuando uso memoria externa, ¿he olvidado algún aspecto crucial de SQLiteDatabase
o simplemente es para que la tarjeta SD sea lenta?
Puedo agregar que en mi aplicación real he desactivado locking y hace poca diferencia.
A menos que tenga una muy buena razón para poner en su base de datos de almacenamiento externo, yo no haría eso. El almacenamiento externo en Android 1.xy 2.x no siempre está disponible (por ejemplo, el usuario monta el almacenamiento como una unidad en su computadora de escritorio o portátil). Además, para medir las operaciones de E/S vinculadas, el emulador tendrá poca similitud con el hardware de producción, ya que el emulador no utiliza el flash para nada (interno o externo), sino que está utilizando archivos de imagen de disco en su máquina de desarrollo. – CommonsWare
El problema es que la base de datos podría crecer, probablemente tendrá un límite máximo de aproximadamente 10 MB o más, no quiero ocupar tanto espacio internamente. –