Android Sqlite Performance
Я делал некоторые эксперименты для измерения производительности sqlite на Android. Я был немного разочарован результатами. Я вставил 10.000 запросов в таблицу, и это заняло 130-140 секунд, но с этими условиями;
1. Samsung galaxy s3 в режиме энергосбережения
2. Вставленные данные (или класс) имеют 3 строки и одно число с плавающей точкой (реальное для sqlite)
3. Вставка события выполняется в асинхронном режиме.
4. В асинхронной задаче я показываю диалог прогресса с переданным текстом таймера (System.currentTimeMillis - секунды и т.д. Blala)
class AddStudentsTask extends AsyncTask<Void,Integer,Void>
{
ProgressDialog prgDialog;
int max = 10000;
Student s;
long seconds = System.currentTimeMillis();
@Override
protected void onPreExecute() {
super.onPreExecute();
prgDialog = new ProgressDialog(MainActivity.this);
prgDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
prgDialog.setMessage(seconds+"");
prgDialog.setMax(max);
prgDialog.setCancelable(false);
prgDialog.show();
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate();
prgDialog.setProgress(values[0]);
sList.add(s);
String s = (System.currentTimeMillis()-seconds)/100+"";
if(s.length()>2)
s = s.substring(0,s.length()-1) + "." + s.charAt(s.length()-1);
else if(s.length() == 2)
s = s.charAt(0) + "." + s.charAt(1);
prgDialog.setMessage(s + " seconds passed.");
}
@Override
protected Void doInBackground(Void... voids) {
for(int a = 0;a< max; a++ )
{
Random r = new Random();
s = new Student();
s.setGpa(r.nextFloat()*4);
s.setLastName("asdasd");
s.setFirstName("Oh My God");
s.setAddress("1sadasd");
s.setId(sda.insert(s));
publishProgress(a);
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
prgDialog.dismiss();
sa.notifyDataSetChanged();
}
}
5. Я использую contentValues с методом insertOrThrow в классе helperdb. ЭТО СТАРЫЙ МЕДЛЕННЫЙ КОД
public long insert(Student s)
{
SQLiteDatabase db = sh.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(StudentHelper.FIRSTNAME,s.getFirstName());
cv.put(StudentHelper.LASTNAME,s.getLastName());
cv.put(StudentHelper.ADDRESS,s.getAddress());
cv.put(StudentHelper.GPA,s.getGpa());
s.setId(db.insertOrThrow(StudentHelper.TABLE_NAME, null, cv));
return s.getId();
}
6. Эта задача выполняется в методе действия onCreate.
Так что же я делаю не так или ожидаю от этого слишком многого? Эти результаты в порядке или плохо?
Что я могу сделать, чтобы улучшить мой код?
РЕДАКТИРОВАТЬ
Так что я изменил свой код вставки на это, и он сократился до 4,5 секунд!
public ArrayList<Long> insertMany(ArrayList<Student> stus)
{
ArrayList<Long> ids = new ArrayList();
String sql = "INSERT INTO "+StudentHelper.TABLE_NAME+"" +
"("+StudentHelper.FIRSTNAME+","+StudentHelper.LASTNAME+"," +
" "+StudentHelper.GPA+") values(?,?,?)";
SQLiteDatabase db = sh.getWritableDatabase();
db.beginTransaction();
for(Student s:stus) {
SQLiteStatement stmt = db.compileStatement(sql);
stmt.bindString(1, s.getFirstName());
stmt.bindString(2, s.getLastName());
stmt.bindDouble(3, s.getGpa());
s.setId(stmt.executeInsert());
ids.add(s.getId());
stmt.clearBindings();
}
db.setTransactionSuccessful();
db.endTransaction();
return ids;
}
Ответы
Ответ 1
Используйте SQLite transaction
для ускорения
Используйте BEGIN TRANSACTION & END TRANSACTION для оптимизации SQLite.
По умолчанию каждый оператор SQL заключен в новый блок транзакции во время выполнения SQLite. Когда вы выполняете базовую операцию с БД, такую как INSERT, будет создан блок транзакции и обернут вокруг него.
Разрешение среды выполнения SQLite управлять транзакцией целесообразно только в том случае, если ваша подпрограмма выполняет только одну операцию с БД над набором данных. Однако, если вы выполняете многочисленные операции с БД (скажем, INSERT внутри цикла for), это становится очень дорогим, так как требует повторного открытия, записи и закрытия файла журнала для каждого оператора. Вы можете сослаться
-
База данных Android SQLite: медленная вставка
-
http://www.androidcode.ninja/android-sqlite-transaction-tutorial/
-
http://www.techrepublic.com/blog/software-engineer/turbocharge-your-sqlite-inserts-on-android/
-
http://www.android-app-market.com/sqlite-optimization-in-android-programming-sqlite-optimization-in-android-apps.html
Ответ 2
Вы можете использовать SQL транзакции на Android, как это. Лучше вставлять несколько строк в базу данных в больших партиях, а затем делать одиночную фиксацию (запись в файл данных SQLlite, который очень медленный) для каждой вставленной строки.
public void insert(List<Student> students)
{
SQLiteDatabase db = sh.getWritableDatabase();
ContentValues cv = new ContentValues();
db.beginTransaction();
try {
for (Student s : students) {
cv.put(StudentHelper.FIRSTNAME,s.getFirstName());
cv.put(StudentHelper.LASTNAME,s.getLastName());
cv.put(StudentHelper.ADDRESS,s.getAddress());
cv.put(StudentHelper.GPA,s.getGpa());
db.insertOrThrow(StudentHelper.TABLE_NAME, null, cv)
}
setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
Ответ 3
Ну, у вас столько записей и для каждой записи вы вызываете getWritableDatabase()
, а затем вставляете ее, что плохо для производительности.
Вам нужно использовать транзакции. Посмотрите на этот вопрос Android-база данных SQLite: медленная вставка. В основном вам нужно позвонить beginTransaction()
, выполнить ваши вставки, а затем вызвать setTransactionSuccessful()
, которому предшествует endTransaction()
. Вы будете удивлены, увидев, сколько выгоды вы получите с этим.