База данных Android SQLite: медленная вставка
мне нужно разобрать довольно большой XML-файл (в диапазоне от около ста килобайт до нескольких сотен килобайт), который я делаю с помощью Xml#parse(String, ContentHandler). В настоящее время я тестирую это с файлом 152KB.
во время синтаксического анализа я также вставляю данные в базу данных SQLite, используя вызовы, подобные следующим:getWritableDatabase().insert(TABLE_NAME, "_id", values). Все это вместе занимает около 80 секунд для тестового файла 152KB (который сводится к вставке примерно 200 строк).
когда я комментирую все вставки заявления (но оставить во всем остальном, например, создание ContentValues etc.) один и тот же файл занимает всего 23 секунды.
нормально ли для операций с базой данных иметь такие большие накладные расходы? Я могу что-нибудь с этим сделать?
5 ответов:
вы должны сделать пакетную вставку.
псевдокод:
db.beginTransaction(); for (entry : listOfEntries) { db.insert(entry); } db.setTransactionSuccessful(); db.endTransaction();что увеличило скорость вставок в моих приложениях чрезвычайно.
обновление:
@Yuku предоставил очень интересный пост в блоге:Android с помощью inserthelper для более быстрых вставок в базу данных sqlite
Так как InsertHelper упоминается Юку и Бреттустаревший теперь (уровень API 17), кажется, правильная альтернатива, рекомендованная Google, использует SQLiteStatement.
я использовал метод вставки базы данных следующим образом:
database.insert(table, null, values);после того, как я также испытал некоторые серьезные проблемы с производительностью, следующий код ускорил мои 500 вставками из 14.5 сек только 270 МС, удивительные!
вот как Я использовал SQLiteStatement:
private void insertTestData() { String sql = "insert into producttable (name, description, price, stock_available) values (?, ?, ?, ?);"; dbHandler.getWritableDatabase(); database.beginTransaction(); SQLiteStatement stmt = database.compileStatement(sql); for (int i = 0; i < NUMBER_OF_ROWS; i++) { //generate some values stmt.bindString(1, randomName); stmt.bindString(2, randomDescription); stmt.bindDouble(3, randomPrice); stmt.bindLong(4, randomNumber); long entryID = stmt.executeInsert(); stmt.clearBindings(); } database.setTransactionSuccessful(); database.endTransaction(); dbHandler.close(); }
компиляция инструкции SQL insert помогает ускорить процесс. Это также может потребовать больше усилий, чтобы укрепить все и предотвратить возможную инъекцию, так как теперь все это на ваших плечах.
другой подход, который также может ускорить процесс,-это недокументированный android.база данных.База данных.Класс InsertHelper. Мое понимание заключается в том, что он на самом деле обертывания составлены инструкции Insert. Происходит от нескомпилированных операции вставки для компиляции операции вставки было около 3х увеличение в скорости (2МС в вставку к.6 мс на вставку) для моих больших (200K+ записей), но простых вставок SQLite.
пример кода:
SQLiteDatabse db = getWriteableDatabase(); //use the db you would normally use for db.insert, and the "table_name" //is the same one you would use in db.insert() InsertHelper iHelp = new InsertHelper(db, "table_name"); //Get the indices you need to bind data to //Similar to Cursor.getColumnIndex("col_name"); int first_index = iHelp.getColumnIndex("first"); int last_index = iHelp.getColumnIndex("last"); try { db.beginTransaction(); for(int i=0 ; i<num_things ; ++i) { //need to tell the helper you are inserting (rather than replacing) iHelp.prepareForInsert(); //do the equivalent of ContentValues.put("field","value") here iHelp.bind(first_index, thing_1); iHelp.bind(last_index, thing_2); //the db.insert() equilvalent iHelp.execute(); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } db.close();
Если в таблице есть индекс, рассмотрите возможность его удаления перед вставкой записей, а затем добавьте его обратно после того, как вы завершили свои записи.
при использовании ContentProvider:
@Override public int bulkInsert(Uri uri, ContentValues[] bulkinsertvalues) { int QueryType = sUriMatcher.match(uri); int returnValue=0; SQLiteDatabase db = mOpenHelper.getWritableDatabase(); switch (QueryType) { case SOME_URI_IM_LOOKING_FOR: //replace this with your real URI db.beginTransaction(); for (int i = 0; i < bulkinsertvalues.length; i++) { //get an individual result from the array of ContentValues ContentValues values = bulkinsertvalues[i]; //insert this record into the local SQLite database using a private function you create, "insertIndividualRecord" (replace with a better function name) insertIndividualRecord(uri, values); } db.setTransactionSuccessful(); db.endTransaction(); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } return returnValue; }затем частная функция для выполнения вставки (внутри вашего контент-провайдера):
private Uri insertIndividualRecord(Uri uri, ContentValues values){ //see content provider documentation if this is confusing if (sUriMatcher.match(uri) != THE_CONSTANT_IM_LOOKING_FOR) { throw new IllegalArgumentException("Unknown URI " + uri); } //example validation if you have a field called "name" in your database if (values.containsKey(YOUR_CONSTANT_FOR_NAME) == false) { values.put(YOUR_CONSTANT_FOR_NAME, ""); } //******add all your other validations //********** //time to insert records into your local SQLite database SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert(YOUR_TABLE_NAME, null, values); if (rowId > 0) { Uri myUri = ContentUris.withAppendedId(MY_INSERT_URI, rowId); getContext().getContentResolver().notifyChange(myUri, null); return myUri; } throw new SQLException("Failed to insert row into " + uri); }
Comments