Вставка 1000000 строк в базу данных sqlite3

Я хочу вставить 10 00 000 строк в базу данных, но вставка занимает слишком много времени.

например Теперь я пробую это с 2055 строками, и для загрузки этих данных в базу данных требуется 3 минуты ... и это время слишком много для 2055 записей.

Ниже приведен мой метод вставки данных в базу данных:

      public void insert_database(Context context,String field1,String field2,String field3,String field4,String field5,String field6 ,String field7,String field8,String field9,String field10)
{

    try
    {
        //RayAllen_Database.beginTransaction();
        RayAllen_Database.execSQL(" insert or replace into "+ TableName_csv+" values( '"+field1+"' ,'"+field2+"','"+field3+"','"+field4+"','"+field5+"','"+field6+"','"+field7+"','"+field8+"','"+field9+"','"+field10+"');");


    }
    catch(Exception e)
    {
        //Log.i("Database Exception", "Exception");
        e.printStackTrace();
    }

}

и в другом классе под названием: Анализ данных: здесь я анализирую файл csv и при анализе:

пытаться {

CSVReader reader=new CSVReader(new FileReader(filename));
String [] nextLine;

//create database
obj.create_database(context);
obj.OpenDatabase(context);
//reader.readNext();

while ((nextLine=reader.readNext())!=null)
{
          //here I am calling the insert_database function
    }
 }

так что здесь он анализирует строку одну за другой и вызывает метод вставки для вставки записи в базу данных.

Но это занимает слишком много времени. Как я могу улучшить производительность этого??


person Kanika    schedule 24.05.2012    source источник
comment
Подготовьте оператор один раз и используйте его для всех вставок в сеансе. Это сделает его быстрее. developer.android.com/reference/java/sql/PreparedStatement.html   -  person Sarwar Erfan    schedule 24.05.2012
comment
У вас есть причина для анализа CSV и заполнения БД на устройстве? Можно ли это сделать офлайн?   -  person Rajesh    schedule 24.05.2012
comment
Но я получаю CSV-файл, поэтому мне нужно прочитать его построчно, чтобы сохранить в базе данных.   -  person Kanika    schedule 24.05.2012
comment
@SarwarErfan: Не могли бы вы привести пример подготовленного заявления?   -  person Kanika    schedule 24.05.2012
comment
Вставка 10 миллионов строк много для простого смартфона... Где создается CSV-файл? Не могли бы вы скопировать/создать базу данных SQLite на сервере и вместо этого отправить готовую к запуску базу данных?   -  person Sam    schedule 24.05.2012
comment
Я думаю, что вставка или замена очень замедляются, потому что в каждой строке он должен проверять, существует ли уже строка, предположительно БЕЗ какого-либо индекса   -  person Rafael T    schedule 24.05.2012
comment
@Sam: я получаю файл csv через вложение электронной почты, затем сохраняю этот файл на SD-карту, а затем начинаю читать файл с помощью программы чтения csv. Но здесь моя главная проблема - это время. Как я могу улучшить производительность, например: теперь при загрузке 2000 данных загрузка занимает 3 минуты, и я думаю, что это слишком много   -  person Kanika    schedule 24.05.2012
comment
Если база данных построена на более быстром процессоре (или наборе процессоров), скажем, на сервере, то после загрузки вложения электронной почты время обработки будет нулевым.   -  person Sam    schedule 24.05.2012
comment
@RafaelT: Теперь я использую только вставку, и все же загрузка этого файла из 2055 записей занимает 3 минуты ???   -  person Kanika    schedule 24.05.2012
comment
@Kanika: Пожалуйста, перейдите на компьютер, на котором у вас есть доступ в Интернет, и попробуйте эту ссылку. (Если бы у вас был интернет, возможно, вы бы сначала погуглили) google .com/#q=android+prepared+statement+insert+example   -  person Sarwar Erfan    schedule 24.05.2012
comment
FFS: начните использовать транзакции и разделите вставки на подходящие фрагменты, например › 1000 вставок поп. Это намного быстрее. Создайте подготовленный оператор и используйте его повторно.   -  person Jens    schedule 24.05.2012


Ответы (3)


Краткий пример того, почему вы должны поступать правильно, а не «неправильно». Это было протестировано на ICS 4.0.4, которая имеет ужасную производительность INSERT.

Во-первых, простой SQLiteOpenHelper, который создает таблицу с ограничением UNIQUE для столбца, что время от времени вызывает конфликты.

class SimpleHelper extends SQLiteOpenHelper {
    // InsertHelpers are a really good idea - they format a prepared statement
    // for you automatically.
    InsertHelper mInsert;
    public SimpleHelper(Context context) {
        super(context, "tanika.db", null, 1);
    }
    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        mInsert = new InsertHelper(db, "target");
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE target (\n" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" +
                "val1 TEXT NOT NULL,\n" +
                "val2 TEXT NOT NULL,\n" +
                "val3 TEXT NOT NULL,\n" +
                // Let's make one unique so we can get some juicy conflicts
                "val4 TEXT NOT NULL UNIQUE\n" +
                ")");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

В комплекте с любым старым Activity мы добавляем следующий простой метод тестирования:

long test(final int n) {
    long started = System.currentTimeMillis();
    ContentValues values = new ContentValues();

    for (int i = 0; i < n; i++) {
        values.clear();
        // Every 20th insert, generate a conflict in val4
        String val4 = String.valueOf(started + i);
        if (i % 20 == 0) {
            val4 = "conflict";
        }
        values.put("val1", "Value1");
        values.put("val2", "Value2");
        values.put("val3", "Value3");
        values.put("val4", val4);
        mHelper.mInsert.replace(values);
    }
    return System.currentTimeMillis() - started;
}

Как видите, это будет вызывать конфликт каждые 20 INSERT или около того. Вызов InsertHelper#replace(..) заставляет помощника использовать INSERT OR REPLACE при конфликтах.

Теперь давайте запустим этот тестовый код с окружающей его транзакцией и без нее.

class Test1 extends AsyncTask<Integer, Void, Long> {
    @Override
    protected Long doInBackground(Integer... params) {
        return test(params[0]);
    }
    @Override
    protected void onPostExecute(Long result) {
        System.out.println(getClass().getSimpleName() + " finished in " + result + "ms");
    }
}

class Test2 extends AsyncTask<Integer, Void, Long> {
    protected Long doInBackground(Integer... params) {
        SQLiteDatabase db = mHelper.getWritableDatabase();
        db.beginTransaction();
        long started = System.currentTimeMillis();
        try {
            test(params[0]);
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
        }
        return System.currentTimeMillis() - started;
    }
    @Override
    protected void onPostExecute(Long result) {
        System.out.println(getClass().getSimpleName() + " finished in " + result + "ms");
    }
}

Запускается все так:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    mHelper = new SimpleHelper(this);
    mHelper.getWritableDatabase(); // Forces the helper to initialize.
    new Test1().execute(2055);
    new Test2().execute(2055);
}

А результаты? Без транзакции INSERT занимает 41072 мс. С транзакциями они занимают 940 мс. Короче говоря, FFS, начните использовать InsertHelpers и транзакции.

person Jens    schedule 24.05.2012
comment
InsertHelper устарел, есть ли другой способ сделать более быструю вставку db в android. - person YLS; 27.03.2017

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

Вот как я это делаю:

  1. Скопируйте базу данных приложения в локальную папку с помощью Android Debuger Bridge (adb) следующим образом: adb pull /data/data/<your application provider>/databases/yourdatbase.db C:/users/databases/yourdatbase.db.

  2. Подключитесь к базе данных SQLites C:/users/databases/yourdatbase.db с помощью вашего любимого инструмента GUI/CLI и завершите заполнение 1 000 000 записей.

  3. Скопируйте заполненную базу данных в папку asset среды разработки Android.

  4. Теперь удалите приложение с устройства, чтобы убедиться, что база данных не создается при первой установке.

  5. Измените свой класс SQLiteHepler, чтобы он проверял, существует ли база данных, и если она существует, он использует ее. Если база данных не существует, Помощник копирует ее из папки вашего ресурса вместе с вашими 1 000 000 записей. Вот как я это сделал:

    public class MyDatabaseHelper extends SQLiteOpenHelper {
    
        /*
            Other SQLiteOpenHelper declarations here ...
        */
    
        private static final String DATABASE_NAME   = "application.db";
        private static final String DB_PATH         = "/data/data/" + context.getPackageName() + "/databases/";
    
    
        /*
            Your SQLiteOpenHelper functions/procedures here ...
        */
    
        public boolean isDataBaseExist() {
    
            File dbFile     = new File(DB_PATH + DATABASE_NAME);
            return dbFile.exists();
        }
    
        public void copyDataBase(Context context) throws IOException {
    
            this.getReadableDatabase();
    
            InputStream inFile      = context.getResources().getAssets().open(DATABASE_NAME);
    
            // Path to the just created empty db
            String outFileName      = DB_PATH + DATABASE_NAME;
            OutputStream outFile    = new FileOutputStream(outFileName);
    
            // transfer bytes from the inputfile to the outputfile
            byte[] buffer = new byte[1024];
    
            int length;
    
            while ((length = inFile.read(buffer)) > 0) {
    
                outFile.write(buffer, 0, length);
    
            }
    
            // Close the streams
            outFile.flush();
            outFile.close();
            inFile.close();
        } 
    

Эта база данных будет собрана вместе с вашим приложением, и при первом запуске все данные будут там. Может быть и более простой способ, но я надеюсь, что это кому-то поможет.

person Lukuluba    schedule 24.05.2012

Ускорение операций вставки sqlite проходит через аналогичный случай и показывает, как использовать транзакции для оптимизации вставки.

person andyandy    schedule 24.05.2012