2010-10-04 43 views
49

Quiero insertar a granel unos 700 registros en la base de datos de Android en mi próxima actualización. ¿Cuál es la forma más eficiente de hacer esto? Desde varias publicaciones, sé que si utilizo las declaraciones Insert, debería envolverlas en una transacción. También hay un post sobre el uso de su propia base de datos, pero necesito esta información para acceder a la base de datos estándar de Android de mi aplicación. Tenga en cuenta que esto solo se haría una vez por dispositivo.Inserción masiva en dispositivo Android

Algunas ideas:

  1. poner un montón de sentencias SQL en un archivo, leerlos en una línea a la vez, y EXEC SQL.

  2. Ponga los datos en un archivo CSV, o JSON, o YAML, o XML, o lo que sea. Lea una línea a la vez y haga db.insert().

  3. Averigüe cómo realizar una importación y realizar una importación única de todo el archivo.

  4. Haga una base de datos sqlite que contenga todos los registros, cópielos en el dispositivo Android y de alguna manera combine las dos bases de datos.

  5. [EDIT] Ponga todas las sentencias de SQL en un solo archivo en res/values ​​como una cadena grande. Luego léelos una línea a la vez y ejecute el SQL.

¿Cuál es la mejor manera? ¿Hay otras formas de cargar datos? ¿Son 3 y 4 incluso posibles?

Respuesta

8

No creo que haya ninguna manera factible de lograr # 3 o # 4 en su lista.

De las otras soluciones, enumera dos que tienen el archivo de datos contiene SQL directo, y el otro tiene los datos en un formato no SQL.

Los tres funcionarían bien, pero la última sugerencia de capturar los datos de un archivo formateado y crear el SQL usted mismo parece ser el más limpio. Si se agrega la capacidad de actualización por lotes real en una fecha posterior, su archivo de datos aún se puede usar, o al menos se puede procesar fácilmente en una forma utilizable. Además, la creación del archivo de datos es más directa y menos propensa a errores. Finalmente, tener los datos "en bruto" permitiría la importación a otros formatos de almacenamiento de datos.

En cualquier caso, debe (como ha mencionado) ajustar los grupos de inserciones en las transacciones para evitar la creación del diario de transacciones por filas.

33

He encontrado que para las inserciones masivas, la clase (aparentemente poco utilizada) DatabaseUtils.InsertHelper es varias veces más rápida que con SQLiteDatabase.insert. otros

Dos optimizaciones también ayudó con el rendimiento de mi aplicación, aunque pueden no ser apropiado en todos los casos:

  • No bind valores que están vacíos o null.
  • Si puede ser cierto que es seguro hacerlo, desactivar temporalmente el bloqueo interno de la base de datos también puede ayudar al rendimiento.

Tengo un blog post con más detalles.

+0

Gracias! Esta optimización aumentó la importación de un grupo de registros en 2 veces. –

+0

Leí el blog y los comentarios. Ambos proporcionaron detalles suficientes para insertar todos mis datos en un par de segundos. Muchas veces mejor que varios minutos. – Knossos

+4

Ahora que 'InsertHelper' está en desuso, nos vemos obligados a usar' SQLiteStatement' –

97

Normalmente, cada vez que se utiliza db.insert(), SQLite crea una transacción (y el archivo de diario resultante en el sistema de archivos), lo que ralentiza las cosas.

Si usa db.beginTransaction() y db.endTransaction() SQLite crea solo un único archivo de diario en el sistema de archivos y luego confirma todas las inserciones al mismo tiempo, acelerando drásticamente las cosas.

Aquí hay un código de pseudo desde: Batch insert to SQLite database on 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(); 
} 

Si desea abortar una operación debido a un error inesperado o algo así, simplemente db.endTransaction() sin establecer primero la operación como un éxito (db.setTransactionSuccessful()).

Otro método útil es usar db.inTransaction() (devuelve true o false) para determinar si se encuentra actualmente en el medio de una transacción.

Documentation here

+0

la base de datos está bloqueada después de hacer esto, cómo desbloquearla .. – Kishore

+2

Para más Referencia de Código: [Inserte por lotes en la base de datos SQLite en Android] (http://notes.theorbis.net/2010/02/batch-insert-to-sqlite-on-android.html) –

+1

Trató de corregir errores en 'db.endTransaction()' pero es demasiado pequeño una edición – acw

9

Bueno, mi solución para esto es un poco raro, pero funciona bien ... puedo compilar una gran suma de datos e insertarlo en una sola vez (a granel insertar?)

utilizo el comando db.execSQL(Query) y construir la "consulta" con la siguiente afirmación ...

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

el único problema es la construcción de la consulta que puede ser un poco desordenado. espero que ayude

+0

Cool. Qué gran solución creativa.Parece que sería bastante rápido. ¿Lo es? –

+1

Sería tan rápido con la clase StringBuilder. –

+0

@Andrew Prat ... Cuál es el límite máximo para UNION. para mí, mediante esta operación sindical, puedo insertar 500 registros en una declaración de inserción. si quiero insertar 5000 registros en una declaración. ¿puede ser posible? ¿Si es así, entonces cómo? –

9

Este ejemplo siguiente funcionará perfectamente

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(); 
Cuestiones relacionadas