Массовая вставка на устройство Android - PullRequest
49 голосов
/ 05 октября 2010

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

Некоторые идеи:

  1. Поместите кучу операторов SQL в файл, прочитайте их в строке за рази выполните SQL.

  2. Поместите данные в файл CSV, или JSON, или YAML, или XML, или что-то еще.Прочитайте строку за раз и выполните db.insert().

  3. . Выясните, как выполнить импорт и выполнить один импорт всего файла.

  4. Создайте базу данных sqlite, содержащую все записи, скопируйте ее на устройство Android и каким-то образом объедините две базы данных.

  5. [EDIT] Поместите все операторы SQL в один файл.в res / values ​​как одна большая строка.Затем прочитайте их по очереди и выполните SQL.

Как лучше?Есть ли другие способы загрузки данных?Возможны ли 3 и 4?

Ответы [ 5 ]

97 голосов
/ 21 сентября 2011

Обычно каждый раз, когда используется db.insert(), SQLite создает транзакцию (и файл журнала в файловой системе), что замедляет работу.

Если вы используете db.beginTransaction() и db.endTransaction() SQLite создаеттолько один файл журнала в файловой системе, а затем фиксирует все вставки одновременно, что значительно ускоряет процесс.

Вот некоторый псевдокод из: Пакетная вставка в базу данных SQLite на Android

try
{
  db.beginTransaction();

  for each record in the list
  {
    do_some_processing();

    if (line represent a valid entry)
    {
      db.insert(SOME_TABLE, null, SOME_VALUE);
    }

    some_other_processing();
  }

  db.setTransactionSuccessful();
}
catch (SQLException e) {}
finally
{
  db.endTransaction();
}

Если вы хотите прервать транзакцию из-за непредвиденной ошибки или чего-то еще, просто db.endTransaction() без предварительной установки транзакции как успешной (db.setTransactionSuccessful()).

Еще один полезный методдолжен использовать db.inTransaction() (возвращает true или false), чтобы определить, находитесь ли вы в середине транзакции.

Документация здесь

34 голосов
/ 16 декабря 2010

Я обнаружил, что для массовых вставок класс DatabaseUtils.InsertHelper (очевидно, мало используемый) работает в несколько раз быстрее, чем SQLiteDatabase.insert.

Две другие оптимизации также помогли с производительностью моего приложения, хотя они могут не подходить во всех случаях:

  • Не bind пустые значения или null.
  • Если вы можете быть уверенным в том, что это безопасно, временное отключение внутренней блокировки базы данных также может повысить производительность.

У меня есть сообщение в блоге с более подробной информацией.

9 голосов
/ 29 августа 2015

Этот пример ниже будет отлично работать

 String sql = "INSERT INTO " + DatabaseHelper.TABLE_PRODUCT_LIST
                + " VALUES (?,?,?,?,?,?,?,?,?);";

        SQLiteDatabase db = this.getWritableDatabase();
        SQLiteStatement statement = db.compileStatement(sql);
        db.beginTransaction();
        for(int idx=0; idx < Produc_List.size(); idx++) {
            statement.clearBindings();
            statement.bindLong(1, Produc_List.get(idx).getProduct_id());
            statement.bindLong(2,  Produc_List.get(idx).getCategory_id());
            statement.bindString(3, Produc_List.get(idx).getName());
//            statement.bindString(4, Produc_List.get(idx).getBrand());
            statement.bindString(5, Produc_List.get(idx).getPrice());
            //statement.bindString(6, Produc_List.get(idx).getDiscPrice());
            statement.bindString(7, Produc_List.get(idx).getImage());
            statement.bindLong(8, Produc_List.get(idx).getLanguage_id());
            statement.bindLong(9, Produc_List.get(idx).getPl_rank());
            statement.execute();

        }
        db.setTransactionSuccessful();
        db.endTransaction();
9 голосов
/ 16 апреля 2012

Ну, мое решение для этого немного странно, но работает нормально ... Я собираю большую сумму данных и вставляю ее за один раз (массовая вставка?)и я строю «Запрос» со следующим утверждением ...

INSERT INTO yourtable SELECT * FROM (
    SELECT 'data1','data2'.... UNION
    SELECT 'data1','data2'.... UNION
    SELECT 'data1','data2'.... UNION
    .
    .
    .
    SELECT 'data1','data2'....
)

Единственная проблема - это построение запроса, который может быть немного грязнымНадеюсь, это поможет

8 голосов
/ 05 октября 2010

Я не верю, что есть какой-либо реальный способ достичь # 3 или # 4 в вашем списке.

Из других решений, перечисленных вами, два, в которых файл данных содержит прямой SQL, а в другом - данные в формате, отличном от SQL.

Все три сработали бы просто отлично, но последнее предложение по сбору данных из отформатированного файла и созданию SQL-кода само по себе кажется самым чистым. Если позднее добавится возможность пакетного обновления, ваш файл данных будет по-прежнему пригоден для использования или, по крайней мере, легко перерабатывается в удобную форму. Кроме того, создание файла данных является более простым и менее подверженным ошибкам. Наконец, наличие «сырых» данных позволит импортировать их в другие форматы хранилища данных.

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

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