Domanda

Sto usando l'archiviazione esterna per la memorizzazione di eventi in un database mentre sono in attesa di essere inviati al server.

Vedo prestazioni davvero sbagliate quando inserisco i record. So che la memoria esterna può essere lenta ma volevo vedere un po 'di numero, quindi ho scritto una piccola app che la mette alla prova.

Ecco il codice:

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();

Il database è esattamente come quello che sta usando la mia vera app, ho provato a rimuovere l'indice ma non ha fatto alcuna differenza.

Ecco i risultati:

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 

Come puoi vedere, l'emulatore non ci si può fidare, InsertHelper Dovrebbe essere più veloce se non altro.
Questo è, ovviamente, prevedibile, il test è stato eseguito principalmente per curiosità.

Ciò che mi ha preoccupato, tuttavia, sono le cattive prestazioni sul mio telefono quando ho usato la memoria esterna, ho perso un aspetto cruciale di SQLiteDatabase O è semplicemente così che la scheda SD sia lenta?

Posso aggiungerlo nella mia vera app che ho disabilitato bloccaggio E fa poca differenza.

È stato utile?

Soluzione

Commonware ha ragione nel suo commento. Qualcosa che fa una grande differenza per le prestazioni di DB è l'utilizzo delle transazioni. Avvolgi il ciclo di inserimento in una transazione. Non sono sicuro al 100% se funzionerebbe con l'inserthelper, ma puoi provare a sostituire il tuo loop con questo:

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();
}

Altri suggerimenti

Ho alcuni problemi di prestazioni DB, quindi ho usato il tuo codice per misurare gli inserti al secondo sul mio sistema. Ma ho anche aggiunto avvolgimento in {inizio, end} transaction ().

Nell'emulatore. Ho ottenuto:

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

E su una Galaxy Samsung 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top