如何在Android中加速SQLite数据库插入?

时间:2015-07-14 21:07:18

标签: java android performance sqlite

当在字典查询应用程序中生成大量结果时,我似乎在某个时刻卡在每个插入500-1000毫秒。是否有任何我不理解的插入技巧或窍门?

以下是插入的示例

long id = this.getDbAdapter().insertData(
    "combo",
     result.getWord(),
     String.valueOf(result.getNumLetters()),
     String.valueOf(result.getPointsScrabble()),
     String.valueOf(result.getPointsWordsWithFriends())
);
if (id < 0) {
    Log.i(TAG, "Database combo insertion of " + result.getWord() + " unsuccessful :(");
} else {
    Log.i(TAG, "Database combo insertion of " + result.getWord() + " successful :)");

}

这是我的数据库适配器:我试图遵循Android准则......

/**
 * SQLite Database. There are many like it but this one is mine...
 *
 * @author John Doe
 * @author Citizen X
 * @version 0.2 (pre-beta)
 * @see 'http://developer.android.com/reference/android/database/sqlite/package-summary.html'
 * @since 0.1 2015-06-17.
 */

public class ResultsDbAdapter {

    // Debugging tag
    public final static String TAG = "DictionaryDbAdapter";

    // Result types
    private static final String RESULT_TYPE_ANAGRAM = "anagram";
    private static final String RESULT_TYPE_SUBWORD = "subword";
    private static final String RESULT_TYPE_COMBO   = "combo";

    // Handle for helper
    ResultsDbHelper helper;

    // Constructor gets access to inner helper class
    public ResultsDbAdapter(Context context) {
        helper = new ResultsDbHelper(context);
    }

    /* -------------- */
    /* --- Helper --- */
    /* -------------- */

    /**
     * SQLite open helper class
     */
     static class ResultsDbHelper extends SQLiteOpenHelper {

        public static final String TAG = "ResultsDbHelper";

        // If you change the database schema, you must increment the database version.
        public static final int DATABASE_VERSION = 55;
        public static final String DATABASE_NAME = "wordsleuth.db";

        /* ------------------------------ */
        /* --- Contract and constants --- */
        /* ------------------------------ */
        /**
         * Database contract
         */
        public class ResultsDbContract {

            // To prevent someone from accidentally instantiating the contract class,
            // give it an empty constructor.
            public ResultsDbContract() {}

            /* --- Inner class that defines the table contents --- */

            /*
            By implementing the BaseColumns interface, your inner class can inherit a primary key
            field called _ID that some Android classes such as cursor adaptors will expect it to have.
            It's not required, but this can help your database work harmoniously with the Android
            framework.
            */
            public abstract class ResultEntry implements BaseColumns {
                // Table name
                public static final String TABLE_NAME = "results";
                // Table columns
                public static final String UID = "_id";
                public static final String COLUMN_NAME_RESULT_TYPE = "resultype";
                public static final String COLUMN_NAME_WORD = "word";
                public static final String COLUMN_NAME_WORD_LENGTH = "length";
                public static final String COLUMN_NAME_SCRABBLE_POINTS = "scrabblepoints";
                public static final String COLUMN_NAME_WORDS_WITH_FRIENDS_POINTS = "wordspoints";
                // Table text
                private static final String ID_INCREMENT = " INTEGER PRIMARY KEY AUTOINCREMENT";
                private static final String TEXT_TYPE = " TEXT";
                private static final String INTEGER_TYPE = " INTEGER";
                private static final String AND = " AND ";
                private static final String COMMA_SEP = ", ";
                private static final String PARENTHESIS_LEFT = " (";
                private static final String PARENTHESIS_RIGHT = " )";
                // Table commands
                private static final String CREATE_TABLE = "CREATE TABLE ";
                private static final String DROP_TABLE = "DROP TABLE IF EXISTS ";
                private static final String DELETE_FROM_ALL = "DELETE * FROM ";
                // Table creation
                private static final String SQL_CREATE_ENTRIES =
                        CREATE_TABLE + TABLE_NAME + PARENTHESIS_LEFT +             // Create table
                            UID + ID_INCREMENT + COMMA_SEP +                       // _id
                            COLUMN_NAME_RESULT_TYPE + TEXT_TYPE + COMMA_SEP +      // result type
                            COLUMN_NAME_WORD + TEXT_TYPE + COMMA_SEP +             // word
                            COLUMN_NAME_WORD_LENGTH + TEXT_TYPE + COMMA_SEP +      // word length
                            COLUMN_NAME_SCRABBLE_POINTS + TEXT_TYPE + COMMA_SEP +  // sc points
                            COLUMN_NAME_WORDS_WITH_FRIENDS_POINTS + TEXT_TYPE +    // wwf points
                        PARENTHESIS_RIGHT;
                // Table deletion
                private static final String SQL_DELETE_ENTRIES = DROP_TABLE + TABLE_NAME;
                private static final String SQL_DELETE_ALL_ENTRIES = DROP_TABLE + TABLE_NAME;

            }
        }// End contract

        /* ------------------- */
        /* --- Constructor --- */
        /* ------------------- */

        /**
         *
         * @param context - the context
         */
        public ResultsDbHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            Log.i(TAG, "Database " + DATABASE_NAME + " version " + DATABASE_VERSION + " created");
        }



    /* -------------------------- */
    /* --- Database insertion --- */
    /* -------------------------- */

    /**
     * Insert a result into the database
     * @param resultType
     * @param word
     * @param length
     * @param scrabblePoints
     * @param wordsPoints
     * @return
     */
    public long insertData(
            // Insertion types       // Info
            // ---------------       --------------
            String resultType,       // Result type
            String word,             // The word
            String length,           // The length
            String scrabblePoints,   // Scrabble(TM) point value
            String wordsPoints       // Words With Friends(TM) point value
    ) {
        // Insert data
        SQLiteDatabase db = helper.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put(COLUMN_NAME_RESULT_TYPE, resultType);
        contentValues.put(COLUMN_NAME_WORD, word);
        contentValues.put(COLUMN_NAME_WORD_LENGTH, length);
        contentValues.put(COLUMN_NAME_SCRABBLE_POINTS, scrabblePoints);
        contentValues.put(COLUMN_NAME_WORDS_WITH_FRIENDS_POINTS, wordsPoints);
        // Returns -1 if fails, otherwise, returns
        return db.insert(TABLE_NAME, null, contentValues);
    }//End insertData()

    // Handle for helper
    ResultsDbHelper helper;

    // Constructor gets access to inner helper class
    public ResultsDbAdapter(Context context) {
        helper = new ResultsDbHelper(context);
    }

    /* -------------- */
    /* --- Helper --- */
    /* -------------- */

    /**
     * SQLite open helper class
     */
     static class ResultsDbHelper extends SQLiteOpenHelper {

        public static final String TAG = "ResultsDbHelper";

        // If you change the database schema, you must increment the database version.
        public static final int DATABASE_VERSION = 55;
        public static final String DATABASE_NAME = "wordsleuth.db";

        /* ------------------------------ */
        /* --- Contract and constants --- */
        /* ------------------------------ */
        /**
         * Database contract
         */
        public class ResultsDbContract {

            // To prevent someone from accidentally instantiating the contract class,
            // give it an empty constructor.
            public ResultsDbContract() {}

            /* --- Inner class that defines the table contents --- */

            /*
            By implementing the BaseColumns interface, your inner class can inherit a primary key
            field called _ID that some Android classes such as cursor adaptors will expect it to have.
            It's not required, but this can help your database work harmoniously with the Android
            framework.
            */
            public abstract class ResultEntry implements BaseColumns {
                // Table name
                public static final String TABLE_NAME = "results";
                // Table columns
                public static final String UID = "_id";
                public static final String COLUMN_NAME_RESULT_TYPE = "resultype";
                public static final String COLUMN_NAME_WORD = "word";
                public static final String COLUMN_NAME_WORD_LENGTH = "length";
                public static final String COLUMN_NAME_SCRABBLE_POINTS = "scrabblepoints";
                public static final String COLUMN_NAME_WORDS_WITH_FRIENDS_POINTS = "wordspoints";
                // Table text
                private static final String ID_INCREMENT = " INTEGER PRIMARY KEY AUTOINCREMENT";
                private static final String TEXT_TYPE = " TEXT";
                private static final String INTEGER_TYPE = " INTEGER";
                private static final String AND = " AND ";
                private static final String COMMA_SEP = ", ";
                private static final String PARENTHESIS_LEFT = " (";
                private static final String PARENTHESIS_RIGHT = " )";
                // Table commands
                private static final String CREATE_TABLE = "CREATE TABLE ";
                private static final String DROP_TABLE = "DROP TABLE IF EXISTS ";
                private static final String DELETE_FROM_ALL = "DELETE * FROM ";
                // Table creation
                private static final String SQL_CREATE_ENTRIES =
                        CREATE_TABLE + TABLE_NAME + PARENTHESIS_LEFT +             // Create table
                            UID + ID_INCREMENT + COMMA_SEP +                       // _id
                            COLUMN_NAME_RESULT_TYPE + TEXT_TYPE + COMMA_SEP +      // result type
                            COLUMN_NAME_WORD + TEXT_TYPE + COMMA_SEP +             // word
                            COLUMN_NAME_WORD_LENGTH + TEXT_TYPE + COMMA_SEP +      // word length
                            COLUMN_NAME_SCRABBLE_POINTS + TEXT_TYPE + COMMA_SEP +  // sc points
                            COLUMN_NAME_WORDS_WITH_FRIENDS_POINTS + TEXT_TYPE +    // wwf points
                        PARENTHESIS_RIGHT;
                // Table deletion
                private static final String SQL_DELETE_ENTRIES = DROP_TABLE + TABLE_NAME;
                private static final String SQL_DELETE_ALL_ENTRIES = DROP_TABLE + TABLE_NAME;

            }
        }// End contract

        /* ------------------- */
        /* --- Constructor --- */
        /* ------------------- */

        /**
         *
         * @param context - the context
         */
        public ResultsDbHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            Log.i(TAG, "Database " + DATABASE_NAME + " version " + DATABASE_VERSION + " created");
        }


        /**
         * On creation
         * @param db -  the database
         */
        public void onCreate(SQLiteDatabase db) {
            Log.i(TAG, "" + db.getPath() + " created");
            db.execSQL(ResultsDbContract.ResultEntry.SQL_CREATE_ENTRIES);
        }


    /* -------------------------- */
    /* --- Database insertion --- */
    /* -------------------------- */

    /**
     * Insert a result into the database
     * @param resultType
     * @param word
     * @param length
     * @param scrabblePoints
     * @param wordsPoints
     * @return
     */
    public long insertData(
            // Insertion types       // Info
            // ---------------       --------------
            String resultType,       // Result type
            String word,             // The word
            String length,           // The length
            String scrabblePoints,   // Scrabble(TM) point value
            String wordsPoints       // Words With Friends(TM) point value
    ) {
        // Insert data
        SQLiteDatabase db = helper.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put(COLUMN_NAME_RESULT_TYPE, resultType);
        contentValues.put(COLUMN_NAME_WORD, word);
        contentValues.put(COLUMN_NAME_WORD_LENGTH, length);
        contentValues.put(COLUMN_NAME_SCRABBLE_POINTS, scrabblePoints);
        contentValues.put(COLUMN_NAME_WORDS_WITH_FRIENDS_POINTS, wordsPoints);
        // Returns -1 if fails, otherwise, returns
        return db.insert(TABLE_NAME, null, contentValues);
    }//End insertData()



}

2 个答案:

答案 0 :(得分:3)

您可以实现的最简单,最有效的性能提升之一是管理数据库事务。 For more on Transactions.

这可以通过使用以下内容来实现:

db.beginTransaction();
try {
  InsertData();
  db.setTransactionSuccessful();
} catch {
  //Error in between database transaction 
} finally {
  db.endTransaction();
}

此外,通过修改到数据库的标准连接字符串可以产生一些提高速度。 This是各种速度提升的绝佳资源,

答案 1 :(得分:-1)

已知在多个插入之间重用SQLiteStatement可提高插入速度。

SQLiteDatabase db = helper.getWritableDatabase();
db.beginTransaction();
try {
    final SQLiteStatement insertStatement = db.compileStatement("INSERT INTO x (a,b) VALUES (?, ?);");
    for (Item item : itemsToInsert) {
        insertStatement.clearBindings();
        insertStatement.bindLong(1, item.getA());
        insertStatement.bindString(2, item.getB());
        insertStatement.executeInsert();
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}

与为每行插入新的插入语句相比,性能提升通常是2-3倍,如果你插入了很多行。