1

In short:

Performing 23770 SELECT queries using query() and retrieving result using a Cursor takes 7 sec. I was able to reduce the time to 1 sec for the same by compiling the statement using compileStatement() and calling simpleQueryForString().
Is there a way to get similar performance without using compileStatement() since compileStatement() is limited to retrieving result only if output is 1x1 table?

More info:

I have an Android app which uses an SQLite database with a table having the following schema:

CREATE TABLE testtable(
    id number primary key,
    sentence text not null
);

The table is indexed on id.
What a part of my app does is to get an array of id's as input and retrieve the corresponding sentences from the table testtable.

I started by using the query() method which took around 7 sec to retrieve sentences for an array of 23770 ids. (23770 queries in 7 seconds)

I was trying to improve performance and I came to know that SQLiteStatement compileStatement(String sql) can improve performance by compiling the statements beforehand. And since SQLiteStatement has a method String simpleQueryForString() to retrieve results if the output is 1 x 1 table(which satisfies my usecase currently), I used it. The improvement was massive. It could complete the same 23770 queries in 1 sec.

Although I can use this for now, the query may get complicated in future and the output may conatin more rows and columns which will make me use query() method.

So my question is: Is there a way to optimize queries without using compileStatement() and get similar performance?

This is the code I am testing with (The code using compileStatement() is commented):

public class DBMan extends SQLiteAssetHelper{

    SQLiteDatabase db;

    public DBMan(Context context){
        super(context, "my.db", null, 1);
        db = this.getReadableDatabase();
    }

    public String[] getSentences(Integer[] idList){

        String[] result = new String[idList.length];

        Cursor cur = null;

        long timeStart = System.nanoTime();

        try {
            db.beginTransaction();

            /* SQLiteStatement selStmt = db.compileStatement("SELECT sentence FROM testtable WHERE id=?"); */

            for (int i = 0; i < idList.length; i++) {

                // Querying using compileStatement() and simpleQueryForString()
                /* 
                selStmt.clearBindings();
                selStmt.bindLong(1, idList[i]);
                result[i] = selStmt.simpleQueryForString();
                */

                // Querying using query() and Cursor
                cur = db.query(
                        "testtable",
                        new String[]{"sentence"},
                        "id = ?",
                        new String[]{String.valueOf(idList[i])},
                        null, null, null
                );

                if (cur.moveToFirst()) {
                    result[i] = cur.getString(0);
                }

                if (cur != null) {
                    cur.close();
                }

            }
            db.setTransactionSuccessful();
        }
        finally {
            db.endTransaction();
        }

        long totalTime = System.nanoTime() - timeStart;
        Log.i("MYAPP", "DB total query time: "+totaltime/1000000000.0+" sec");

        return result;
    }
}

I'm using SQLiteAssetHelper which is an extension of SQLiteOpenHelper. I'm using it to copy my database file from assets folder on first run instead of creating it.

I'm used transactions although I'm doing only select queries as it reduces the number of shared locks that are obtained and dropped(see here).

Elben
  • 173
  • 1
  • 8

0 Answers0