La forma más rápida de buscar cadenas almacenadas en la base de datos sqlite

I have large number of strings, approximately 15,000 that I stored in a SQLite database using the following code:

 void addKey(String key, String value, String table) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_KEY, key); // Contact Name
        values.put(KEY_VALUE, value); // Contact Phone

        // Inserting Row
        db.insert(table, null, values);
        db.close(); // Closing database connection

    }

And then i search through that database using the following method in order to pick out any strings that match the key im looking for:

public String searchKeyString(String key, String table){
        String rtn = "";
        Log.d("searchKeyString",table);

            // Select All Query
            String selectQuery = "SELECT  * FROM " + table;

            SQLiteDatabase db = this.getWritableDatabase();
            Cursor cursor = db.rawQuery(selectQuery, null);

            // looping through all rows and adding to list
            if (cursor.moveToFirst()) {
                do {
                    Log.d("searchKeyString","searching");

                    if(cursor.getString(1).equals(key)) 
                        rtn = rtn + "," + cursor.getString(2);
                } while (cursor.moveToNext());
            }
            cursor.close();
            db.close();
            Log.d("searchKeyString","finish search");

        return rtn;
    }

The goal is to do this in real time as the user is typing on the keep board so response time is key and the way it stands now it takes over a second to run through the search.

I considered reading all of the items into an array list initially and sorting through that which might be faster, but i thought an array list of that size might cause memory issues. What is the best way to search through these entries in my database?

preguntado el 04 de diciembre de 12 a las 04:12

are you looking for something like an AutoCompleteTextView? -

Actually yes... or similar atleast Im working on doing text prediction for a custom keyboard -

4 Respuestas

A couple of things you can do...

  • Change the return to a StringBuilder until the end.
  • Only use a readable version of the database (that's probably not making much difference though)
  • Do not get a new instance of the database every time, keep it opened until you don't need it anymore
  • Query for only what you need with the "WHERE" argument in the SQL query.

See the code below with some changes:

// move this somewhere else in your Activity or such
SQLiteDatabase db = this.getReadableDatabase();

public String searchKeyString(String key, String table){
    StringBuilder rtn = new StringBuilder();
    Log.d("searchKeyString",table);

        // Select All Query
        String selectQuery = "SELECT  * FROM " + table + " WHERE KEY_KEY=?";

        Cursor cursor = db.rawQuery(selectQuery,  new String[] {key});
        // you can change it to
        // db.rawQuery("SELECT * FROM "+table+" WHERE KEY_KEY LIKE ?", new String[] {key+"%"});
        // if you want to get everything starting with that key value

        // looping through all rows and adding to list
        if (cursor.moveToFirst()) {
            do {
                Log.d("searchKeyString","searching");

                rtn.append(",").append(cursor.getString(2));
            } while (cursor.moveToNext());
        }
        cursor.close();
        Log.d("searchKeyString","finish search");

    return rtn.toString();
}

Note even if you want this to happen in "real-time" for the user, you will still need to move this to a separate Thread or ASyncTask or you are going to run into problems....

Respondido el 04 de diciembre de 12 a las 05:12

This worked thanks, I'm going to look into putting it in a ASyncTask - Peter

I actually have something a bit similar, so when you put it in an ASyncTask, a few things you need to be careful about or at least keep in mind... you should only run one query at a time; the query can take a long time; a query coming "later" can still finish ahead; you should not query for something that's already obsolete (when the user typed more)...etc... good luck! - Mateo

One more thing... to make the SQLite query faster, if you only do search for equality is to build an index on that column, check sqlite.org/lang_createindex.html - Mateo

Deberías considerar usar SELECT * FROM your-table LIMIT 50, for example. And you can put two buttons "Back", "Next" on your view. If every page has max 50 items, the user is at page 1, and he taps "Next", then you can use this query:

SELECT * FROM your-table LIMIT 50 OFFSET 50

If your table contains most of text-data, and you want to integrate search deeply into your app, consider using virtual table with Fts.

Respondido el 04 de diciembre de 12 a las 04:12

Let sqlite do the hard lifting.

First off, add an index to the field you're searching for, if you don't have one already. Secondly, don't do a SELECT all with manual table scan, but rather use a query in the form

SELECT column_value
  FROM my_table
 WHERE column_key LIKE "ABC%"

This returns the least amount of data, and the sql engine uses the index.

Respondido el 04 de diciembre de 12 a las 04:12

I don't mean to be rude or ask too much but could you write that in the place of my search class so i can better understand how it works and how to use it? - Peter

i dunno about better but maybe it'd be Más rápida to make queries for the selected strings one by one.

public String searchKeyString(String key, String table){
    String rtn = "";
    Log.d("searchKeyString",table);

    // Select All Query
    String selectQuery = "SELECT  * FROM " + table + "WHERE column_1 = " + key;

    SQLiteDatabase db = this.getWritableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);

    // looping through all rows and adding to list
    if (cursor.moveToFirst()) {
        rtn = rtn + "," + cursor.getString(2);
    }
    cursor.close();
    db.close();
    Log.d("searchKeyString","finish search");

    return rtn;
}

EDIT:

Well i dunno how those custom keyboard apps do it, but those AutoCompleteTextViews are hooked up to adapters. you could just as easily make a cursorAdapter and hook your auto-complete view to it.

http://www.outofwhatbox.com/blog/2010/11/android-autocompletetextview-sqlite-and-dependent-fields/

http://www.opgenorth.net/blog/2011/09/06/using-autocompletetextview-and-simplecursoradapter-2/

Respondido el 04 de diciembre de 12 a las 05:12

You should never build SQL queries like this. Use prepared statements instead of string concatenation. For more details see: owasp.org/index.php/Guide_to_SQL_Injection y owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet - Mario Vilas

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.