Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLite Optimization for Android application

We have about 7-8 tables in our Android application each having about 8 columns on an average. Both read and write operations are performed on the database and I am experimenting and trying to find ways to enhance the performance of the DataAccess layer. So, far I have tried the following:

  1. Use positional arguments in where clauses (Reason: so that sqlite makes use of the same execution plan)
  2. Enclose inserts and update with transactions(Reason: every db operation is enclosed within a transaction by default. Doing this will remove that overhead)
  3. Indexing: I have not created any explicit index other than those created by default on the primary key and unique keys columns.(Reason: indexing will improve seek time)

I have mentioned my assumptions in paranthesis; please correct me if I am wrong.

Questions:

  1. Can I add anything else to this list? I read somewhere that avoiding the use of db-journal can improve performance of updates? Is this a myth or fact? How can this be done, if recomended?

  2. Are nested transactions allowed in SQLite3? How do they affect performance? The thing is I have a function which runs an update in a loop, so, i have enclosed the loop within a transaction block. Sometimes this function is called from another loop inside some other function. The calling function also encloses the loop within a transaction block. How does such a nesting of transactions affect performance?

  3. The where clauses on my queries use more than one columns to build the predicate. These columns might not necessarily by a primary key or unique columns. Should I create indices on these columns too? Is it a good idea to create multiple indices for such a table?

like image 482
Samuh Avatar asked Oct 25 '10 13:10

Samuh


People also ask

Is SQLite good for Android?

Android SQLite is a very lightweight database which comes with Android OS. Android SQLite combines a clean SQL interface with a very small memory footprint and decent speed. For Android, SQLite is “baked into” the Android runtime, so every Android application can create its own SQLite databases.

Is SQLite good for mobile apps?

SQLite is very good for testing. Zero-configuration: SQLite doesn't need any complex set up to store the data. When you build Native applications with Java, it comes integrated with the platform. Developers call SQLite, a serverless database and it really lives up to the expectation.

How can I make SQLite database faster?

Instead of writing changes directly to the db file, write to a write-ahead-log instead and regularily commit the changes. This allows multiple concurrent readers even during an open write transaction, and can significantly improve performance.

Is SQLite deprecated in Android?

In which case, does that mean that SQLLite is deprecated in Android? No.


2 Answers

  1. Pin down exactly which queries you need to optimize. Grab a copy of a typical database and use the REPL to time queries. Use this to benchmark any gains as you optimize.

  2. Use ANALYZE to allow SQLite's query planner to work more efficiently.

  3. For SELECTs and UPDATEs, indexes can things up, but only if the indexes you create can actually be used by the queries that you need speeding up. Use EXPLAIN QUERY PLAN on your queries to see which index would be used or if the query requires a full table scan. For large tables, a full table scan is bad and you probably want an index. Only one index will be used on any given query. If you have multiple predicates, then the index that will be used is the one that is expected to reduce the result set the most (based on ANALYZE). You can have indexes that contain multiple columns (to assist queries with multiple predicates). If you have indexes with multiple columns, they are usable only if the predicates fit the index from left to right with no gaps (but unused columns at the end are fine). If you use an ordering predicate (<, <=, > etc) then that needs to be in the last used column of the index. Using both WHERE predicates and ORDER BY both require an index and SQLite can only use one, so that can be a point where performance suffers. The more indexes you have, the slower your INSERTs will be, so you will have to work out the best trade-off for your situation.

  4. If you have more complex queries that can't make use of any indexes that you might create, you can de-normalize your schema, structuring your data in such a way that the queries are simpler and can be answered using indexes.

  5. If you are doing a large number of INSERTs, try dropping indexes and recreating them at the end. You will need to benchmark this.

  6. SQLite does support nested transactions using savepoints, but I'm not sure that you'll gain anything there performance-wise.

  7. You can gain lots of speed by compromising on data integrity. If you can recover from database corruption yourself, then this might work for you. You could perhaps only do this when you're doing intensive operations that you can recover from manually.

I'm not sure how much of this you can get to from an Android application. There is a more detailed guide for optimizing SQLite in general in the SQLite documentation.

like image 65
Robie Basak Avatar answered Oct 21 '22 03:10

Robie Basak


Here's a bit of code to get EXPLAIN QUERY PLAN results into Android logcat from a running Android app. I'm starting with an SQLiteOpenHelper dbHelper and an SQLiteQueryBuilder qb.

String sql = qb.buildQuery(projection,selection,selectionArgs,groupBy,having,sortOrder,limit);
android.util.Log.d("EXPLAIN",sql + "; " + java.util.Arrays.toString(selectionArgs));
Cursor c = dbHelper.getReadableDatabase().rawQuery("EXPLAIN QUERY PLAN " + sql,selectionArgs);
if(c.moveToFirst()) {
    do {
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < c.getColumnCount(); i++) {
            sb.append(c.getColumnName(i)).append(":").append(c.getString(i)).append(", ");
        }
        android.util.Log.d("EXPLAIN",sb.toString());
    } while(c.moveToNext());
}
c.close();

I dropped this into my ContentProvider.query() and now I can see exactly how all the queries are getting performed. (In my case it looks like the problem is too many queries rather than poor use of indexing; but maybe this will help someone else...)

like image 33
Robert Tupelo-Schneck Avatar answered Oct 21 '22 03:10

Robert Tupelo-Schneck