«Оптимизация» доступа к курсорам в Android: позиция против имен столбцов - PullRequest
7 голосов
/ 02 февраля 2012

С точки зрения производительности: нормально ли, если при каждом доступе к моим курсорам я использую что-то вроде:

public static final String COLUMN_NAME = "my_column_name";
cursor.getString(cursor.getColumnIndex(COLUMN_NAME));

Или я должен увидеть измеримое улучшение производительности, еслиЯ использую это вместо:

public static final int COLUMN_POSITION = #column_position;
cursor.getString(COLUMN_POSITION);

Я предпочитаю первый подход, так как остальная часть кода не зависит от позиции столбцов в запросе, а только от имени столбца.Итак, мой вопрос: стоит ли жертвовать этим ради «повышения производительности» доступа к курсору, используя вместо этого постоянные позиции?Какой подход вы предпочитаете в своих приложениях для Android?

Ответы [ 2 ]

28 голосов
/ 01 августа 2013

Чтобы ответить на ваш вопрос (и мой, кстати), я сделал несколько тестов.

Этот тест был в основном для проверки того, сколько времени запрос занял в этих двух случаях:

  1. Использование метода cursor.getString(cursor.getColumnIndex(COLUMN_NAME))
  2. Сначала получить идентификатор столбца, а затем напрямую вызвать cursor.getString(COLUMN_POSITION) метод

Чтобы сделать тест производительности значимым, я вставил 5000 строк в базу данных, а затем сделал запрос, бросив ContentProvider на эти элементы.

Результаты:

 ___________________________________________________________________________
| Column count| Time (ms) getColumnIndex | Time (ms) columnId | improvement |
|_____________|__________________________|____________________|_____________|
| 500         | 34564                    | 30401              | 13%         |
| 200         |  9987                    |  8502              | 17%         |
| 100         |  4713                    |  4004              | 17%         |
| 50          |  2400                    |  1971              | 21%         |
| 20          |  1088                    |   915              | 19%         |
|___________________________________________________________________________|

Итак, сначала получение идентификатора столбца и прямой вызов метода getString() займет примерно 20% меньше времени.


Детали метода испытаний:

Платформа: Nexus 7 (2012) на Android 4.3

Создание базы данных:

public static int TESTSPEEDCOLUMNCOUNT = 200;
StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE " + Tables.TESTSPEED + " (");
sb.append(BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, ");
for (int i = 0; i < (TESTSPEEDCOLUMNCOUNT - 1); ++i) {
    sb.append("C" + i + " TEXT, ");
}
sb.append("C" + (TESTSPEEDCOLUMNCOUNT - 1) + " TEXT)");
db.execSQL(sb.toString());

TestCase:

public class ProviderTestSpeed extends ProviderTestCase2<MyProvider> {

    private ContentValues createElementForId(String id) {
        ContentValues cv = new ContentValues();
        for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
            cv.put("C" + i, id);
        }
        return cv;
    }



    public void testSpeed() {
        Log.d(TAG, "testSpeed start columnCount = " + columnCount);
        ArrayList<ContentValues> list = new ArrayList<ContentValues>();
        ContentValues[] tabcv = {};
        for (int j = 0; j < 10; ++j) {
            list.clear();
            for (int i = 0; i < 500; ++i) {
                ContentValues cv = createElementForId(String.valueOf(i));
                list.add(cv);
            }
            mContentResolver.bulkInsert(TestSpeedCONTENT_URI, list.toArray(tabcv));
        }
        Log.d(TAG, "testSpeed insertFinished");
        Cursor cursor = mContentResolver.query(TestSpeedCONTENT_URI, null, null, null, null);
        cursor.moveToFirst();
        Log.d(TAG, "testSpeed itemCount = " + cursor.getCount() + " columnCount=" + cursor.getColumnCount());

        // build the tab to avoid dynamic allocation during the mesure
        ArrayList<String> listColumns = new ArrayList<String>();
        for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
            listColumns.add("C" + i);
        }
        String[] tabColumnsType = {};
        String[] tabColumns = listColumns.toArray(tabColumnsType);

        Date now = new Date();
        long start = now.getTime();
        do {
            for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
                // get the all the columns of the table
                cursor.getString(cursor.getColumnIndex(tabColumns[i]));
            }
        } while (cursor.moveToNext());
        now = new Date();
        long end = now.getTime();

        Log.d(TAG, "testSpeed took " + (end - start) + " with getColumnIndex at each time");
        cursor.moveToFirst();
        now = new Date();
        start = now.getTime();
        do {
            for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
                // get the all the columns of the table using directly the column id
                cursor.getString(i);
            }
        } while (cursor.moveToNext());
        now = new Date();
        end = now.getTime();
        Log.d(TAG, "testSpeed took " + (end - start) + " with getColumnIndex before loop");
    }
}

Я думаю, что падение производительности между 200 и 500 происходит из окна курсора. У меня было много журналов, как это выше 200 столбцов:

W/CursorWindow(1628): Window is full: requested allocation 2412 bytes, free space 988 bytes, window size 2097152 bytes
2 голосов
/ 02 февраля 2012

Я думаю, это не имеет ничего общего с Android. в SQLite доступ к столбцу через индекс (положение столбца) должен быть быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...