Оптимизация SQLite для приложения Android - PullRequest
10 голосов
/ 25 октября 2010

В нашем приложении для Android имеется около 7-8 таблиц, каждая из которых имеет в среднем около 8 столбцов. И операции чтения, и записи выполняются в базе данных, и я экспериментирую и пытаюсь найти способы повышения производительности уровня DataAccess. Итак, пока я пробовал следующее:

  1. Использовать позиционные аргументы в предложениях where (Причина: так sqlite использует один и тот же план выполнения)
  2. Заключение операций вставки и обновления транзакциями (причина: каждая операция с БД по умолчанию заключена в транзакцию. Это устранит накладные расходы)
  3. Индексирование: я не создал никаких явных индексов, кроме тех, которые созданы по умолчанию для столбцов первичного ключа и уникального ключа. (Причина: индексирование улучшит время поиска)

Я упомянул свои предположения в парантезе; пожалуйста, поправьте меня, если я ошибаюсь.

Вопросы:

  1. Могу ли я добавить что-нибудь еще в этот список? Я где-то читал, что отказ от использования db-journal может улучшить производительность обновлений? Это миф или факт? Как это можно сделать, если рекомендуется?

  2. Разрешены ли вложенные транзакции в SQLite3? Как они влияют на производительность? Дело в том, что у меня есть функция, которая запускает обновление в цикле, поэтому я заключил цикл в блок транзакции. Иногда эта функция вызывается из другого цикла внутри какой-то другой функции. Вызывающая функция также заключает цикл в блок транзакции. Как такое вложение транзакций влияет на производительность?

  3. Предложения where в моих запросах используют более одного столбца для построения предиката. Эти столбцы не обязательно могут быть первичным ключом или уникальными столбцами. Должен ли я создавать индексы для этих столбцов тоже? Это хорошая идея, чтобы создать несколько индексов для такой таблицы?

Ответы [ 4 ]

12 голосов
/ 03 ноября 2010
  1. Укажите, какие именно запросы необходимо оптимизировать. Возьмите копию типичной базы данных и используйте REPL для определения времени запросов. Используйте это для оценки любых прибылей при оптимизации.

  2. Используйте ANALYZE, чтобы планировщик запросов SQLite работал более эффективно.

  3. Для SELECT s и UPDATE s индексы могут работать, но только если созданные вами индексы действительно могут использоваться запросами, которые вам нужно ускорить. Используйте EXPLAIN QUERY PLAN в своих запросах, чтобы увидеть, какой индекс будет использоваться, или если запрос требует полного сканирования таблицы. Для больших таблиц полное сканирование таблицы плохо, и вам, вероятно, нужен индекс. Для каждого запроса будет использоваться только один индекс. Если у вас есть несколько предикатов, то будет использоваться индекс, который, как ожидается, уменьшит результирующий набор больше всего (на основе ANALYZE). Вы можете иметь индексы, которые содержат несколько столбцов (чтобы помочь запросам с несколькими предикатами). Если у вас есть индексы с несколькими столбцами, они могут использоваться только в том случае, если предикаты соответствуют индексу слева направо без пропусков (но неиспользуемые столбцы в конце подходят). Если вы используете предикат порядка (<, <=, > и т. Д.), То он должен находиться в последнем использованном столбце индекса. Для использования обоих предикатов WHERE и ORDER BY требуется индекс, а SQLite может использовать только один, так что это может стать причиной снижения производительности. Чем больше у вас индексов, тем медленнее будут ваши INSERT s, поэтому вам придется найти лучший компромисс для вашей ситуации.

  4. Если у вас есть более сложные запросы, которые не могут использовать какие-либо индексы, которые вы можете создать, вы можете отменить нормализацию своей схемы, структурируя данные таким образом, чтобы запросы были проще и на них можно было отвечать используя индексы.

  5. Если вы выполняете большое количество INSERT с, попробуйте сбросить индексы и воссоздать их в конце. Вам нужно будет проверить это.

  6. SQLite поддерживает вложенные транзакции с использованием точек сохранения, но я не уверен, что вы получите что-то там с точки зрения производительности.

  7. Вы можете получить большую скорость, ставя под угрозу целостность данных . Если вы можете восстановить поврежденную базу данных самостоятельно, это может сработать для вас. Возможно, это можно сделать только тогда, когда вы выполняете интенсивные операции, которые можно восстановить вручную.

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

8 голосов
/ 08 марта 2012

Вот небольшой код для получения результатов EXPLAIN QUERY PLAN в Android LogCat из запущенного приложения для Android.Я начинаю с 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();

. Я опустил это в свой ContentProvider.query(), и теперь я точно вижу, как выполняются все запросы.(В моем случае, похоже, проблема в слишком большом количестве запросов , а не в плохом использовании индексации; но, возможно, это поможет кому-то еще ...)

1 голос
/ 03 ноября 2010

Я бы добавил это:

  1. Использование rawQuery () вместо сборки с использованием ContentValues ​​в некоторых случаях ускоряет работу. Конечно, писать сырой запрос немного утомительно.

  2. Если у вас много данных типа строки / текста, рассмотрите возможность создания виртуальных таблиц с помощью полнотекстового поиска (FTS3), который может выполнять более быстрый запрос. Вы можете искать в Google точные улучшения скорости.

0 голосов
/ 02 июля 2013

Небольшой момент, который следует добавить к исчерпывающему ответу Роби: VFS в SQLite (который в основном связан с блокировкой) можно заменить на альтернативные. Вы можете найти одну из альтернатив, например unix-excl или unix-none , чтобы быть быстрее, но прислушайтесь к предупреждениям на странице SQLite VFS !

Нормализация (структур таблиц) также стоит рассмотреть (если вы этого еще не сделали) просто потому, что она обеспечивает наименьшее представление данных в базе данных; это компромисс, меньшее количество операций ввода-вывода для большего количества ЦП, и тот, который обычно стоит в средних корпоративных базах данных (тот тип, с которым я больше всего знаком), но я боюсь, я не знаю, Компромисс хорошо работает на небольших платформах, таких как Android.

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