适用于Android应用程序的SQLite优化

Sam*_*muh 10 sqlite optimization android

我们的Android应用程序中大约有7-8个表,每个表平均有大约8列.读取和写入操作都在数据库上执行,我正在尝试并尝试找到增强DataAccess层性能的方法.所以,我尝试了以下几点:

  1. 在where子句中使用位置参数(原因:这样sqlite使用相同的执行计划)
  2. 使用事务封装插入和更新(原因:默认情况下,每个数据库操作都包含在事务中.执行此操作将消除该开销)
  3. 索引:除了在主键和唯一键列上默认创建的索引之外,我没有创建任何显式索引.(原因:索引将改善搜索时间)

我已经提到了我在paranthesis中的假设; 如果我错了,请纠正我.

问题:

  1. 我可以在此列表中添加其他内容吗?我在某地读过,避免使用db-journal可以提高更新的性能?这是神话还是事实?如果推荐的话怎么办呢?

  2. SQLite3中是否允许嵌套事务?它们如何影响性能?问题是我有一个在循环中运行更新的函数,因此,我已将循环包含在事务块中.有时这个函数是从另一个函数中的另一个循环中调用的.调用函数还将循环包含在事务块中.这种事务嵌套如何影响性能?

  3. 我的查询中的where子句使用多个列来构建谓词.这些列可能不一定是主键或唯一列.我也应该在这些列上创建索引吗?为这样的表创建多个索引是一个好主意吗?

Rob*_*sak 12

  1. 确切地确定您需要优化哪些查询.获取典型数据库的副本并使用REPL计时查询.在优化时使用它来对任何收益进行基准测试.

  2. 使用ANALYZE允许的SQLite的查询规划,以更有效地工作.

  3. 对于SELECTs和UPDATEs,索引可以解决问题,但前提是您创建的索引实际上可以被您需要加速的查询使用.EXPLAIN QUERY PLAN在查询上使用以查看将使用哪个索引或查询是否需要全表扫描.对于大型表,全表扫描很糟糕,您可能需要索引.任何给定查询都只使用一个索引.如果您有多个谓词,那么将使用的索引是预期会最大程度地减少结果集的索引(基于ANALYZE).您可以拥有包含多个列的索引(以帮助查询多个谓词).如果您有多列的索引,只有当谓词从左到右适合索引且没有间隙时才可以使用它们(但最后未使用的列很好).如果您使用的排序谓词(<,<=,>等),那么需要在该指数的最后使用的列.使用两个WHERE谓词并且ORDER BY两者都需要索引,而SQLite只能使用一个索引,因此这可能是性能受损的点.您拥有的索引越多,您INSERT的索引就越慢,因此您必须根据自己的情况进行最佳权衡.

  4. 如果您有更复杂的查询无法使用您可能创建的任何索引,则可以对模式进行反规范化,以使查询更简单并且可以使用索引来回答的方式构建数据.

  5. 如果您正在执行大量的INSERTs,请尝试删除索引并在最后重新创建它们.你需要对此进行基准测试.

  6. SQLite 确实支持使用保存点的嵌套事务,但我不确定你会在性能方面获得任何好处.

  7. 通过妥协数据完整性,可以获得很多速度.如果您可以自己从数据库损坏中恢复,那么这可能对您有用.您可能只在执行可以手动恢复的密集操作时执行此操作.

我不确定你能从Android应用程序中获得多少.SQLite文档中有一个更详细的 SQLite优化指南.


RTS*_*lio 9

这里有一些代码可以EXPLAIN QUERY PLAN从正在运行的Android应用程序中将结果导入Android logcat.我从一个SQLiteOpenHelper dbHelper和一个开始SQLiteQueryBuilder qb.

String sql = qb.buildQuery(projection,selection,selectionArgs,groupBy,having,sortOrder,limit);
android.util.Log.d("EXPLAIN",sql + "; " + java.util.Arrays.toString(selectionArgs));
Cursor c = dbHelper.getReadableDatabase().rawQuery("EXPLAIN QUERY PLAN " + sql,selectionArgs);
if(c.moveToFirst()) {
    do {
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < c.getColumnCount(); i++) {
            sb.append(c.getColumnName(i)).append(":").append(c.getString(i)).append(", ");
        }
        android.util.Log.d("EXPLAIN",sb.toString());
    } while(c.moveToNext());
}
c.close();
Run Code Online (Sandbox Code Playgroud)

我把它放到我的脑中ContentProvider.query(),现在我可以确切地看到所有查询是如何执行的.(在我的情况下,看起来问题是查询太多而不是索引的使用不当;但也许这会帮助其他人...)