I have been doing some experiments to measure sqlite performance on android. I was disappointed a little bit with the results. What i did was inserting 10.000 queries to table and it took 130-140 seconds but with these conditions;
1. Samsung galaxy s3 in power saving mode
2. Inserted data(or class)has 3 strings and one float(real for sqlite)
3. Insert event is being done in asynctask.
4. In asynctask, i am showing a progress dialog with passed timer text in it (System.currentTimeMillis - seconds etc 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 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. I am using contentValues with insertOrThrow method in helperdb class. THIS IS OLD SLOW CODE
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. This task is done in onCreate method of activity.
So what am i doing wrong here or expecting too much from it? Are these results ok or bad?
What can i do to improve my code?
EDIT
So i changed my insert code to this and it reduced to 4.5 seconds!!!
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;
}
The main idea of SQLite is to get rid of server-client architecture and store all the app information directly on a mobile device. In such a manner, the majority of Android developers have been using it for more than 20 years for the projects where they need to store the data on a device, not on a server.
The SQLite docs explains why this is so slow: Transaction speed is limited by disk drive speed because (by default) SQLite actually waits until the data really is safely stored on the disk surface before the transaction is complete. That way, if you suddenly lose power or if your OS crashes, your data is still safe.
SQLite is fast and reliable and it requires no configuration or maintenance. It keeps things simple. SQLite "just works".
It's not suitable for large scale apps SQLite is light, it's small, it's great for a desktop or a phone — local storage with a small footprint. When it comes to bigger apps with lots of concurrent users and lots of data, SQLite is less optimal. These uses require a much more heavy-duty, server-based DBMS.
Use SQLite transaction
for speed up
Use BEGIN TRANSACTION & END TRANSACTION for SQLite Optimization
Each SQL statement is enclosed in a new transaction block by SQLite runtime, by default. Sowhen you perform a basic DB operation such as INSERT, a transaction block will be created and wrapped around it.
Letting SQLite runtime manage the transaction for you is advisable only if your routine performs only one DB operation on a data set. However, if you are doing numerous DB operations (say INSERT inside for loop), this becomes very expensive, since it requires reopening, writing to, and closing the journal file for each statement. You may refer
Android SQLite database: slow insertion
http://www.androidcode.ninja/android-sqlite-transaction-tutorial/
http://www.techrepublic.com/blog/software-engineer/turbocharge-your-sqlite-inserts-on-android/
http://www.android-app-market.com/sqlite-optimization-in-android-programming-sqlite-optimization-in-android-apps.html
You can use SQL transactions in Android like this. It's better to insert multiple rows into the database in larger batches then making single commit (write into SQLlite datafile which is very slow) for every inserted row.
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)
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With