You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLite查询5000条数据耗时超1分钟,求性能优化方案

SQLite查询5000条数据耗时超1分钟的性能优化方案

问题描述

查询SQLite中5000条数据耗时超过1分钟,无法通过分页限制数据量解决问题,需要针对性的性能优化方案。

现有代码

表创建语句

//Table Create    
private String CREATE_COST_CENTER_TABLE = "CREATE TABLE IF NOT EXISTS "
        + SQLConstants.TABLE_COST_CENTER + "( "
        + SQLConstants.FIELD_COST_CENTER_ID + " INTEGER PRIMARY KEY,"
        + SQLConstants.FIELD_COST_CENTER_NAME + " VARCHAR,"
        + SQLConstants.FIELD_BUSINESS_UNIT_ID + " INTEGER,"
        + SQLConstants.FIELD_COMPANY_ID + " INTEGER)";

数据插入逻辑

//Insertion of Costcentre
public synchronized void saveCostCenterItemList(
        List<CostCenterItem> costCenterItemList) {
    if (costCenterItemList == null)
        return;

    database.delete(SQLConstants.TABLE_COST_CENTER, null, null);

    for (CostCenterItem costCenterItem : costCenterItemList) {
        saveCostCenterItem(costCenterItem);
    }
 }

public long saveCostCenterItem(CostCenterItem costCenterItem) {
    if (costCenterItem == null)
        return -1;

    long rowId = -1;
    database = sqlHelper.getWritableDatabase();
    SQLiteStatement insStmt = database.compileStatement("INSERT INTO " + 
    SQLConstants.TABLE_COST_CENTER
            + " (" + SQLConstants.FIELD_COST_CENTER_ID + "," + 
    SQLConstants.FIELD_COST_CENTER_NAME
            + "," + SQLConstants.FIELD_BUSINESS_UNIT_ID + ","+ 
    SQLConstants.FIELD_COMPANY_ID +
            ") VALUES (?, ?, ?, ?);");
    database.beginTransaction();

    try {
        try {
             insStmt.bindString(1, String.valueOf(costCenterItem.getId()));
            insStmt.bindString(2, costCenterItem.getName());
            insStmt.bindLong(3,  costCenterItem.getBusinessUnitId());
            insStmt.bindString(4, String.valueOf(costCenterItem.getCompanyId()));

            rowId = insStmt.executeInsert();

            database.setTransactionSuccessful();
        } finally {
            database.endTransaction();
        }
    } catch (Exception e1) {
        e1.printStackTrace();
        rowId = -1;
    }

    return rowId;
 }

数据查询逻辑

//Fetch Data  
public ArrayList<CostCenterItem> getCostCenterItemListByBusinessIDandCompanyid1(
        int businessUnitId, int companyId ) {
    ArrayList<CostCenterItem> list = new ArrayList<>();
    Cursor cursor = null;

    try {
        cursor = database.query(SQLConstants.TABLE_COST_CENTER, 
null,
                SQLConstants.FIELD_BUSINESS_UNIT_ID + "=" + 
businessUnitId
                        + " AND "
                        + SQLConstants.FIELD_COMPANY_ID + "="
                        + companyId ,
                null, null, null, null);

        if (cursor != null && cursor.getCount() > 0) {
            for (int i = 0; i < cursor.getCount(); i++) {
                cursor.moveToPosition(i);

                CostCenterItem item = new CostCenterItem();
                item.setId(cursor.getInt(cursor
                        .getColumnIndex(SQLConstants.FIELD_COST_CENTER_ID)));
                item.setName(cursor.getString(cursor
                        .getColumnIndex(SQLConstants.FIELD_COST_CENTER_NAME)));
                item.setBusinessUnitId(cursor.getInt(cursor
                        .getColumnIndex(SQLConstants.FIELD_BUSINESS_UNIT_ID)));
                
                item.setCompanyId(cursor.getInt(cursor.getColumnIndex(SQLConstants.FIELD_COMPANY_ID)));

                list.add(item);
            }
        }
    } catch (SQLiteException e) {
        e.printStackTrace();
    } finally {
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
    }

    return list;
}

已尝试的优化

已为FIELD_COST_CENTER_NAME列创建索引:

private static final String SQL_CREATE_EMAIL_INDEX =
"CREATE INDEX cost_center_cc_name_idx ON " + SQLConstants.TABLE_COST_CENTER + "
(" + SQLConstants.FIELD_COST_CENTER_NAME + ")";

针对性优化方案

1. 创建查询条件的复合索引

当前查询通过businessUnitId和companyId过滤数据,单独字段索引无法发挥最大效用,创建这两个字段的复合索引可大幅提升查询速度:

private static final String SQL_CREATE_COMPOSITE_INDEX =
"CREATE INDEX cost_center_bu_company_idx ON " + SQLConstants.TABLE_COST_CENTER + "
(" + SQLConstants.FIELD_BUSINESS_UNIT_ID + ", " + SQLConstants.FIELD_COMPANY_ID + ")";

2. 优化Cursor遍历方式

避免moveToPosition(i)的随机访问,改用顺序遍历减少Cursor定位开销,同时预获取列索引避免重复查找:

// 修改查询方法中的遍历逻辑
if (cursor != null) {
    // 预获取所有列索引
    int idIndex = cursor.getColumnIndex(SQLConstants.FIELD_COST_CENTER_ID);
    int nameIndex = cursor.getColumnIndex(SQLConstants.FIELD_COST_CENTER_NAME);
    int buIdIndex = cursor.getColumnIndex(SQLConstants.FIELD_BUSINESS_UNIT_ID);
    int companyIdIndex = cursor.getColumnIndex(SQLConstants.FIELD_COMPANY_ID);
    
    // 顺序遍历Cursor
    while (cursor.moveToNext()) {
        CostCenterItem item = new CostCenterItem();
        item.setId(cursor.getInt(idIndex));
        item.setName(cursor.getString(nameIndex));
        item.setBusinessUnitId(cursor.getInt(buIdIndex));
        item.setCompanyId(cursor.getInt(companyIdIndex));
        list.add(item);
    }
}

3. 移除cursor.getCount()调用

cursor.getCount()会触发额外的结果集遍历,直接通过moveToNext()判断是否有数据即可,无需提前获取总数。

4. 优化批量插入逻辑

当前每条数据单独开启事务,修改为批量事务插入减少事务开销:

public synchronized void saveCostCenterItemList(
        List<CostCenterItem> costCenterItemList) {
    if (costCenterItemList == null || costCenterItemList.isEmpty())
        return;

    database = sqlHelper.getWritableDatabase();
    SQLiteStatement insStmt = database.compileStatement("INSERT INTO " + 
    SQLConstants.TABLE_COST_CENTER
            + " (" + SQLConstants.FIELD_COST_CENTER_ID + "," + 
    SQLConstants.FIELD_COST_CENTER_NAME
            + "," + SQLConstants.FIELD_BUSINESS_UNIT_ID + ","+ 
    SQLConstants.FIELD_COMPANY_ID +
            ") VALUES (?, ?, ?, ?);");
            
    database.beginTransaction();
    try {
        database.delete(SQLConstants.TABLE_COST_CENTER, null, null);
        for (CostCenterItem costCenterItem : costCenterItemList) {
            insStmt.bindString(1, String.valueOf(costCenterItem.getId()));
            insStmt.bindString(2, costCenterItem.getName());
            insStmt.bindLong(3,  costCenterItem.getBusinessUnitId());
            insStmt.bindString(4, String.valueOf(costCenterItem.getCompanyId()));
            insStmt.executeInsert();
            insStmt.clearBindings();
        }
        database.setTransactionSuccessful();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        database.endTransaction();
    }
 }

5. 使用参数化查询

避免直接拼接SQL参数,改用参数化查询提升缓存效率并避免SQL注入风险:

cursor = database.query(SQLConstants.TABLE_COST_CENTER, 
null,
        SQLConstants.FIELD_BUSINESS_UNIT_ID + "=? AND " + SQLConstants.FIELD_COMPANY_ID + "=?",
        new String[]{String.valueOf(businessUnitId), String.valueOf(companyId)},
        null, null, null);

内容的提问来源于stack exchange,提问作者Gaurav Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:09:57