2010-10-04 19 views
49

Chcę wstawić zbiorczo około 700 rekordów do bazy danych Androida podczas kolejnej aktualizacji. Jaki jest najskuteczniejszy sposób na zrobienie tego? Z różnych postów wiem, że jeśli używam instrukcji Insert, powinienem zawinąć je w transakcję. Istnieje również post o używaniu własnej bazy danych, ale potrzebuję tych danych, aby przejść do standardowej bazy danych Android mojej aplikacji. Należy pamiętać, że będzie to wykonywane tylko raz na urządzenie.Wstawianie zbiorcze na urządzeniu z systemem Android

Kilka pomysłów:

  1. umieścić kilka instrukcji SQL w pliku, czytać je w jednej linii na raz, a EXEC SQL.

  2. Umieścić dane w pliku CSV, JSON lub YAML, lub XML, lub cokolwiek innego. Czytaj linię naraz i wykonaj db.insert().

  3. Dowiedz się, jak wykonać import i wykonać jeden import całego pliku.

  4. Utwórz bazę danych zawierającą wszystkie rekordy, skopiuj ją na urządzenie z systemem Android i jakoś scal dwie bazy danych.

  5. [EDYCJA] Umieść wszystkie instrukcje SQL w jednym pliku w res/values ​​jako jeden duży ciąg. Następnie odczytaj je po linii i uruchom SQL.

Jaki jest najlepszy sposób? Czy są inne sposoby ładowania danych? Czy 3 i 4 są możliwe?

Odpowiedz

8

Nie sądzę, że istnieje jakikolwiek wykonalny sposób na wykonanie 3 lub 4 na liście.

Z innych rozwiązań wymień dwa, które zawierają plik danych zawierający bezpośredni SQL, a drugi ma dane w formacie innym niż SQL.

Wszystkie trzy działają dobrze, ale ostatnia sugestia pobrania danych z sformatowanego pliku i zbudowania samego SQL wydaje się najczystsza. Jeśli w późniejszym terminie zostanie dodana prawdziwa możliwość aktualizacji partii, plik danych będzie nadal użyteczny lub przynajmniej łatwo przetworzyć go w nadający się do użytku formularz. Ponadto tworzenie pliku danych jest prostsze i mniej podatne na błędy. Wreszcie posiadanie "surowych" danych umożliwiłoby import do innych formatów przechowywania danych.

W każdym przypadku powinieneś (jak wspomniano) owijać grupy wstawek w transakcje, aby uniknąć tworzenia dzienników transakcji między wierszami.

33

Znalazłem, że dla wstawek luzem, (prawdopodobnie mało używana) klasa DatabaseUtils.InsertHelper jest kilka razy szybsza niż przy użyciu SQLiteDatabase.insert.

Dwa inne optymalizacje wydajności pomogły także z mojej aplikacji, choć mogą one nie być odpowiednie we wszystkich przypadkach:

  • Czy nie bind wartości, które są puste lub null.
  • Jeśli możesz być pewne, że jest to bezpieczne, tymczasowe wyłączenie wewnętrznego blokowania bazy danych może również pomóc wydajności.

Mam numer blog post z dodatkowymi informacjami.

+0

Dzięki! Ta optymalizacja spowodowała zwiększenie importu grupy rekordów o 2x. –

+0

Przeczytałem blog i komentarze. Oba dostarczyły informacje wystarczające do wstawienia wszystkich moich danych w ciągu kilku sekund. Wiele razy lepiej niż kilka minut. – Knossos

+4

Teraz, gdy 'InsertHelper' jest przestarzałe, jesteśmy zmuszeni używać' SQLiteStatement'? –

97

Zwykle za każdym razem, gdy używany jest kod db.insert(), SQLite tworzy transakcję (i wynikowy plik kroniki w systemie plików), co spowalnia działanie.

Jeśli używasz db.beginTransaction() i db.endTransaction() SQLite tworzy tylko jeden plik kroniki w systemie plików, a następnie zatwierdza wszystkie wstawki w tym samym czasie, znacznie przyspieszając rzeczy.

Oto niektóre pseudo kod z: 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(); 
} 

Jeśli chcesz przerwać transakcję z powodu nieoczekiwanego błędu czy coś, po prostu db.endTransaction() bez uprzedniego ustawienia transakcję jako skuteczne (db.setTransactionSuccessful()).

Inną przydatną metodą jest użycie db.inTransaction() (zwraca true lub false) w celu ustalenia, czy jesteś w trakcie transakcji.

Documentation here

+0

baza danych jest zablokowana po wykonaniu tej czynności, jak to odblokować. – Kishore

+2

Więcej kodu: [Wstaw wsad do bazy danych SQLite na Androida] (http://notes.theorbis.net/2010/02/batch-insert-to-sqlite-on-android.html) –

+1

Próbowałem naprawić literówkę w 'db.endTransaction()' ale jest za mała edytuj – acw

9

dobrze, moje rozwiązanie tego to niby dziwne, ale działa dobrze ... skompilować dużą sumę danych i wstawić go w jednej porcji (wstawić luzem?)

używam komenda db.execSQL(Query) i zbudować „zapytania” z następującym stwierdzeniem ...

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

jedynym problemem jest budowa zapytania, które mogą być swego rodzaju bałagan. Mam nadzieję, że to pomaga

+0

Cool. Co za świetne twórcze rozwiązanie.Wygląda na to, że byłoby dość szybko. Czy to jest? –

+1

Byłoby tak szybko z klasy StringBuilder. –

+0

@Andrew Prat ... Jaki jest maksymalny limit dla UNION. dla mnie przez tę operację związania mogę włożyć 500 rekordów w jednym wyciągu. jeśli chcę wstawić 5000 rekordów w jednym wyciągu. to będzie możliwe? jeśli tak, to w jaki sposób? –

9

Ten przykład poniżej będzie działać idealnie

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(); 
Powiązane problemy