Android sqlite begintransaction выполняется слишком долго

Я хочу вставить данные, проанализированные из json, в db в пакетном режиме. Я использую метод ниже, чтобы вставить пакет. Проблема в том, что mDbWritable.beginTransaction(); выполняется слишком долго. Обычно как 6 секунд! Я не знаю, где проблема. Некоторые мысли, что может вызвать такое долгое время выполнения? Большое спасибо.

@Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
        throws OperationApplicationException {
    long start = System.currentTimeMillis();
    mDbWritable.beginTransaction();
    long time = System.currentTimeMillis() - start;
    Alog.i(TAG, "Time applyBatch beginTransaction: " + time);

    final int numOperations = operations.size();
    final ContentProviderResult[] results = new ContentProviderResult[numOperations];
    try {
        for (int i = 0; i < numOperations; i++) {
            results[i] = operations.get(i).apply(this, results, i);
        }

        mDbWritable.setTransactionSuccessful();

    } finally {
        mDbWritable.endTransaction();
    }
    return results;
}

Пример из логов:

11-16 15:14:53.726: I/ApiProvider(21442): Time applyBatch beginTransaction: 6025
11-16 15:15:00.713: I/ApiProvider(21442): Time applyBatch beginTransaction: 4940
11-16 15:15:17.819: I/ApiProvider(21442): Time applyBatch beginTransaction: 8651
11-16 15:15:45.346: I/ApiProvider(21442): Time applyBatch beginTransaction: 12672
11-16 15:16:16.807: I/ApiProvider(21442): Time applyBatch beginTransaction: 12411
11-16 15:16:45.685: I/ApiProvider(21442): Time applyBatch beginTransaction: 12247
11-16 15:17:01.500: I/ApiProvider(21442): Time applyBatch beginTransaction: 12788

РЕДАКТИРОВАТЬ: я использую пакетное применение в цикле при разборе json. например для каждого элемента в json - разобрать и применить пакет. Пакет содержит операции вставки, обновления, удаления.

Вот код, как я повторяю и вызываю applyBatch

Cursor starredChannelsCursor =
        mContentResolver.query(ApiContract.Channels.CONTENT_URI,
                               new String[] {BaseColumns._ID, ChannelsTable.ID, ChannelsTable.SLUG },
                               ChannelsTable.IS_STARRED + "=?",new String[] { "1" }, null);

String userName = mSettings.getUserName();

if (starredChannelsCursor != null && starredChannelsCursor.moveToFirst()) {     
    while (!starredChannelsCursor.isAfterLast()) {
        String channelSlug = starredChannelsCursor.getString(2);
        ChannelHandler channelHandler = new ChannelHandler(this);
        URI channelApiUri = Constants.getChannelApiURI(channelSlug,userName);
        //execute update make applybatch call
        executeUpdate(channelApiUri, channelHandler);

        starredChannelsCursor.moveToNext();
    }
}

if (starredChannelsCursor != null) {
    starredChannelsCursor.close();
}


/**
* Make call to Uri, parse response and apply batch operations to
* contentResolver
* 
* @param apiUri
* @param handler
*            - handles parsing
*/
private boolean executeUpdate(URI apiUri, AbstractJSONHandler handler) {
    ApiResponse apiResponse = mHttpHelper.doHttpCall(apiUri);

    ArrayList<ContentProviderOperation> batch =
                    new ArrayList<ContentProviderOperation>();

    if (apiResponse != null) {
        batch = handler.parse(apiResponse);
        Alog.v(TAG, "update user data from " + apiUri);
    }

    if (batch.size() > 0) {
        try {
            mContentResolver.applyBatch(ApiContract.CONTENT_AUTHORITY, batch);
        } catch (Exception e) {
            Alog.v(TAG, "Error: " + e.getMessage());
        }
    }
    return true;
}

person Martin Vandzura    schedule 16.11.2012    source источник
comment
каково значение numOperations?   -  person waqaslam    schedule 16.11.2012
comment
обычно вроде 70 , но проблема только в строке mDbWritable.beginTransaction(); как видите, я измеряю время выполнения этого метода. Другие части быстро   -  person Martin Vandzura    schedule 16.11.2012
comment
я думаю, вам следует взять транзакцию вне метода applyBatch   -  person waqaslam    schedule 16.11.2012
comment
Это код из приложения Google IO 2012 и правильное место для транзакции.   -  person Martin Vandzura    schedule 16.11.2012
comment
Вы запускали профилирование методов на этом? Хватит гадать о том, что происходит, и начните профилировать!   -  person smith324    schedule 26.11.2012


Ответы (1)


Единственная проблема, которая кажется возможной, заключается в том, что разные потоки получают одну и ту же блокировку при вызове beginTransaction() и теряют время, просто ожидая, пока другие потоки снимут блокировку. Взгляните на свой код и посмотрите, как вы управляете потоками и из каких потоков вы вызываете метод applyBatch(..).

Вам также может быть полезно просмотреть иерархию вызовов beginTransaction() по адресу SQLiteDatabase.

person a.ch.    schedule 19.11.2012
comment
Я не знаю, что может заблокировать beginTransaction примерно на 12 секунд. Вероятно, это потому, что я вызываю пакетное применение в цикле, но этого не должно быть, потому что я вызываю beginTransaction после завершения предыдущей транзакции. - person Martin Vandzura; 20.11.2012
comment
Согласно источникам класса SQLiteDatabase, он может быть даже заблокирован на 30 секунд при доступе из разных потоков. Не могли бы вы предоставить код, из которого вы вызываете метод applyBatch(..)? - person a.ch.; 20.11.2012
comment
Разве вы не используете ту же БД где-либо еще в своем приложении? - person a.ch.; 20.11.2012
comment
Я использую контент-провайдера, а не базу данных напрямую. Я уверен, что за время, когда это работает, других сложных запросов не будет. Я имею в виду, что, возможно, предыдущая итерация mDbWritable.setTransactionSuccessful(); или mDbWritable.endTransaction(); выполняется асинхронно, поэтому можно перейти к следующему beginTransaction, но он по-прежнему блокирует db. - person Martin Vandzura; 20.11.2012