安卓Sqlite性能优化

15

我一直在进行一些实验,以测量Android上的SQLite性能。结果让我有点失望。我所做的是向表中插入10000个查询,用时130-140秒但是在这些条件下;

1.三星Galaxy S3处于省电模式

2.插入的数据(或类)有3个字符串和一个浮点数(real for sqlite)

3.插入事件正在异步任务中执行。

4.在异步任务中,我正在显示一个带有传递的计时器文本的进度对话框(System.currentTimeMillis - seconds等等)

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. 我正在helperdb类中使用contentValues与insertOrThrow方法。 这是旧的缓慢代码。

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
不对,你必须执行 beginTransaction,然后进行 10,000 次插入操作,接着执行 setTransactionSuccessful,最后再执行 endTransaction。修改你的 AddStudentsTask 以使其正常运行。 - M-Wajeeh
我明白了,是的,你的意思是我为插入重新打开了1万次。我懂了,谢谢=)。我编辑了帖子,为未来遇到问题的人提供一些使用方面的想法。 - Mert Serimer
1
这个是完美的。 - M-Wajeeh
请查看此链接,或许能帮到您:https://stackoverflow.com/questions/38867973/insert-over-6000-recods-in-sqlite-android - user4813855
Jason Feinstein的博客上有一个很好的性能基准测试: https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-insertions-971aff98eef2 - Mariusz
显示剩余5条评论
3个回答

30

使用 SQLite 事务 来提高速度

使用 BEGIN TRANSACTIONEND TRANSACTION 进行 SQLite 优化

默认情况下,每个 SQL 语句在 SQLite 运行时都会被封装在一个新的事务块中。因此,当您执行基本的数据库操作,例如 INSERT 时,将创建并包装一个事务块。

只有在您的例程对数据集执行了单个 DB 操作时,才建议让 SQLite 运行时为您管理事务。但是,如果您正在进行大量的 DB 操作(例如在 for 循环中插入数据),则这将变得非常昂贵,因为它需要针对每个语句重新打开、写入和关闭日志文件。 您可以参考以下链接:

  1. Android SQLite 数据库:插入缓慢

  2. http://www.androidcode.ninja/android-sqlite-transaction-tutorial/

  3. http://www.techrepublic.com/blog/software-engineer/turbocharge-your-sqlite-inserts-on-android/

  4. http://www.android-app-market.com/sqlite-optimization-in-android-programming-sqlite-optimization-in-android-apps.html


以上只是一个链接,没有其他内容,所以您能否提供一些解释? - duggu
4
谢谢您的回答,它加快了20倍,哈哈。花了7.5秒。 - Mert Serimer
2
我编辑了我的帖子,为未来可能遇到问题的人提供帮助,以便他们可以更改他们的代码。 - Mert Serimer

12

您可以像这样在Android中使用SQL 事务。最好一次将多行插入数据库,而不是每插入一行都进行单个提交(写入非常缓慢的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)
        }
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
    }
}

非常感谢您提供的解决方案。这确实提高了性能。 - Parmendra Singh

2

你有很多记录,每次都调用getWritableDatabase()然后插入,这对性能不利。

你需要使用事务。看看这个问题:Android SQLite database: slow insertion。基本上,你需要调用beginTransaction(),进行插入操作,然后在调用endTransaction()之前调用setTransactionSuccessful()。你会惊讶地发现,这样做可以大大提高性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接