2015-01-28 23 views
11

Ho fatto alcuni esperimenti per misurare le prestazioni in sqlite su Android. Sono rimasto un po 'deluso dai risultati. Quello che ho fatto è stato inserire 10.000 query al tavolo e ci sono voluti 130-140 secondima con queste condizioni;Prestazioni Sqlite Android

1. galassia s3 a risparmio energetico modalità

2. dati inseriti (o classe) ha 3 corde e un galleggiante (reali per SQLite)

3. Inserisci evento è in corso in asynctask.

4. In AsyncTask, sto mostrando un progresso dialogo con testo timer passato in esso (System.currentTimeMillis - secondi ecc blala)

class AddStudentsTask extends AsyncTask<Void,Integer,Void> 
{ 
    ProgressDialog prgDialog; 
    int max = 10000; 
    Student s; 
    long seconds = System.currentTimeMillis(); 


    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
     prgDialog = new ProgressDialog(MainActivity.this); 
     prgDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
     prgDialog.setMessage(seconds+""); 
     prgDialog.setMax(max); 
     prgDialog.setCancelable(false); 
     prgDialog.show(); 

    } 

    @Override 
    protected void onProgressUpdate(Integer... values) { 
     super.onProgressUpdate(); 
     prgDialog.setProgress(values[0]); 
     sList.add(s); 
     String s = (System.currentTimeMillis()-seconds)/100+""; 
     if(s.length()>2) 
      s = s.substring(0,s.length()-1) + "." + s.charAt(s.length()-1); 
     else if(s.length() == 2) 
      s = s.charAt(0) + "." + s.charAt(1); 
     prgDialog.setMessage(s + " seconds passed."); 

    } 

    @Override 
    protected Void doInBackground(Void... voids) { 

     for(int a = 0;a< max; a++) 
     { 
      Random r = new Random(); 
      s = new Student(); 

      s.setGpa(r.nextFloat()*4); 
      s.setLastName("asdasd"); 
      s.setFirstName("Oh My Fuckig God"); 
      s.setAddress("1sadasd"); 
      s.setId(sda.insert(s)); 
      publishProgress(a); 
     } 

     return null; 
    } 

    @Override 
    protected void onPostExecute(Void aVoid) { 
     super.onPostExecute(aVoid); 
     prgDialog.dismiss(); 
     sa.notifyDataSetChanged(); 
    } 
} 

5. Sto usando contentValues ​​con metodo insertOrThrow in classe helperdb. Questo è un codice SLOW VECCHIO

public long insert(Student s) 
{ 
    SQLiteDatabase db = sh.getWritableDatabase(); 
    ContentValues cv = new ContentValues(); 
    cv.put(StudentHelper.FIRSTNAME,s.getFirstName()); 
    cv.put(StudentHelper.LASTNAME,s.getLastName()); 
    cv.put(StudentHelper.ADDRESS,s.getAddress()); 
    cv.put(StudentHelper.GPA,s.getGpa()); 
    s.setId(db.insertOrThrow(StudentHelper.TABLE_NAME, null, cv)); 
    return s.getId(); 
} 

6. Questo compito viene fatto in modo onCreate di attività.

Quindi cosa sto facendo di sbagliato qui o mi aspetto troppo da esso? Questi risultati sono ok o cattivi?

Cosa posso fare per migliorare il mio codice?

EDIT

Così ho cambiato il mio codice Inserisci per questo ed è ridotto a 4,5 secondi !!!

public ArrayList<Long> insertMany(ArrayList<Student> stus) 
{ 
    ArrayList<Long> ids = new ArrayList(); 
    String sql = "INSERT INTO "+StudentHelper.TABLE_NAME+"" + 
      "("+StudentHelper.FIRSTNAME+","+StudentHelper.LASTNAME+"," + 
      " "+StudentHelper.GPA+") values(?,?,?)"; 
    SQLiteDatabase db = sh.getWritableDatabase(); 
    db.beginTransaction(); 

    for(Student s:stus) { 
     SQLiteStatement stmt = db.compileStatement(sql); 

     stmt.bindString(1, s.getFirstName()); 
     stmt.bindString(2, s.getLastName()); 
     stmt.bindDouble(3, s.getGpa()); 

     s.setId(stmt.executeInsert()); 
     ids.add(s.getId()); 
     stmt.clearBindings(); 
    } 

    db.setTransactionSuccessful(); 
    db.endTransaction(); 

    return ids; 
} 
+0

Non vedo 'endTransaction' o' setTransactionSuccessful' se appena aggiunto 'beginTransaction' nel vostro' metodo insert' allora ti sei perso il punto. –

+0

@ M-WaJeEh Hai ragione. Ho modificato il mio post. Grazie per le critiche costruttive !! –

+1

No, ancora sbagliato. Devi fare 'beginTransaction' e poi 10.000 inserzioni e poi' setTransactionSuccessful' e quindi 'endTransaction'. Modifica il tuo 'AddStudentsTask' affinché funzioni. –

risposta

25

Usa SQLite transaction per la velocità fino

Usa BEGIN TRANSACTION & END TRANSACTION per SQLite ottimizzazione

ogni istruzione SQL è racchiuso in un nuovo blocco transazione runtime SQLite, per impostazione predefinita. Se esegui un'operazione DB di base come INSERT, verrà creato un blocco di transazione che verrà avvolto attorno ad esso.

Se si desidera che la runtime di SQLite gestisca la transazione, è consigliabile solo se la routine esegue solo un'operazione DB su un set di dati. Tuttavia, se si eseguono numerose operazioni DB (ad esempio INSERT all'interno di loop), questo diventa molto costoso, poiché richiede la riapertura, la scrittura e la chiusura del file journal per ciascuna istruzione. È possibile fare riferimento

  1. Android SQLite database: slow insertion

  2. http://www.androidcode.ninja/android-sqlite-transaction-tutorial/

  3. http://www.techrepublic.com/blog/software-engineer/turbocharge-your-sqlite-inserts-on-android/

  4. http://www.android-app-market.com/sqlite-optimization-in-android-programming-sqlite-optimization-in-android-apps.html

+0

sopra solo un link nient'altro così ti fornirai qualche spiegazione – duggu

+3

Grazie per risposta. Ha accelerato 20 volte lol. ci sono voluti 7,5 secondi –

+0

@MertSerimer yo benvenuto !!! Mi sono riferito allo stesso modo in alcune delle mie app. –

1

Bene, hai così tanti record e per ogni record chiami getWritableDatabase() e poi inseriscilo, il che è negativo per le prestazioni.

È necessario utilizzare le transazioni. Guarda questa domanda Android SQLite database: slow insertion. Fondamentalmente è necessario chiamare beginTransaction(), fare i tuoi inserimenti e quindi chiamare setTransactionSuccessful() preceduto da endTransaction(). Sarai sorpreso di vedere quanto guadagni in termini di prestazioni otterrai con questo.

8

È possibile utilizzare le transazioni SQL in Android in questo modo. È meglio inserire più righe nel database in lotti più grandi, quindi effettuare il commit singolo (scrivere in un file di dati SQLlite che è molto lento) per ogni riga inserita.

public void insert(List<Student> students) 
{ 
    SQLiteDatabase db = sh.getWritableDatabase(); 
    ContentValues cv = new ContentValues(); 

    db.beginTransaction(); 

    try { 
     for (Student s : students) { 
       cv.put(StudentHelper.FIRSTNAME,s.getFirstName()); 
       cv.put(StudentHelper.LASTNAME,s.getLastName()); 
       cv.put(StudentHelper.ADDRESS,s.getAddress()); 
       cv.put(StudentHelper.GPA,s.getGpa()); 

       db.insertOrThrow(StudentHelper.TABLE_NAME, null, cv) 
     } 
     setTransactionSuccessful(); 
    } finally { 
     db.endTransaction(); 
    } 
}