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

3

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

например Сейчас я пытаюсь сделать это с 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
    }
 }

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

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

У вас есть причина, чтобы сделать разбор CSV и заполнение БД на устройстве? Можно ли сделать это в автономном режиме? Rajesh
Подготовьте оператор один раз и используйте его для всех вставок в сеансе. Это сделает это быстрее.developer.android.com/reference/java/sql/PreparedStatement.html Sarwar Erfan
Но я получаю CSV-файл, поэтому мне нужно читать его построчно, чтобы сохранить его в базе данных Kanika
@SarwarErfan: Не могли бы вы привести пример готового заявления? Kanika
Вставка 10 миллионов строкa lot для простого смартфона ... Где создается файл CSV? Не могли бы вы скопировать / создать базу данных SQLite на сервере и вместо этого отправить готовую к запуску базу данных? Sam

Ваш Ответ

3   ответа
3

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

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

  1. Copy the application database to a local folder using the Android Debuger Bridge (adb) like this: adb pull /data/data/<your application provider>/databases/yourdatbase.db C:/users/databases/yourdatbase.db.

  2. Connect to the SQLites database C:/users/databases/yourdatbase.db with your favourite GUI/CLI tool and complete your population of the 1 000 000 records.

  3. Copy your populated database to your Android development environment asset folder.

  4. Now uninstall your application from the device to make sure there is no database created when you install for the first time.

  5. Modify your SQLiteHepler class so that it checks if a database exists and if one exists it uses that one. If no database exists the Helper copies the one from your asset folder together with your 1 000 000 records. This is how I have done it:

    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();
        } 
    

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

2

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

8

Краткий пример того, почему вы должны поступать правильно, а не «неправильно». Это было протестировано на 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;
}

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

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

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взять41072ms, С транзакциями они берут940ms, Короче, FFS, начни использоватьInsertHelperс и транзакции.

InsertHelper устарел, есть ли другой способ сделать более быструю вставку БД в Android.

Похожие вопросы