2010-10-04 23 views
49

Tôi muốn chèn hàng loạt khoảng 700 bản ghi vào cơ sở dữ liệu Android trong lần nâng cấp tiếp theo của mình. Cách hiệu quả nhất để làm điều này là gì? Từ các bài viết khác nhau, tôi biết rằng nếu tôi sử dụng các câu lệnh Insert, tôi nên bọc chúng trong một giao dịch. Ngoài ra còn có một số post về cách sử dụng cơ sở dữ liệu của riêng bạn, nhưng tôi cần dữ liệu này để chuyển sang cơ sở dữ liệu Android chuẩn của ứng dụng. Lưu ý rằng điều này sẽ chỉ được thực hiện một lần cho mỗi thiết bị.Chèn số lượng lớn trên thiết bị Android

Một số ý tưởng:

  1. Đặt một loạt các câu lệnh SQL trong một tập tin, đọc chúng trong một dòng tại một thời điểm, và exec SQL.

  2. Đặt dữ liệu vào tệp CSV hoặc JSON hoặc YAML hoặc XML hoặc bất kỳ thứ gì. Đọc một dòng tại một thời điểm và làm db.insert().

  3. Tìm hiểu cách nhập và nhập một lần toàn bộ tệp.

  4. Tạo cơ sở dữ liệu sqlite chứa tất cả các bản ghi, sao chép vào thiết bị Android và bằng cách nào đó hợp nhất hai cơ sở dữ liệu.

  5. [EDIT] Đặt tất cả các câu lệnh SQL trong một tệp duy nhất trong res/values ​​dưới dạng một chuỗi lớn. Sau đó đọc từng dòng một và thực hiện câu lệnh SQL.

Cách tốt nhất là gì? Có cách nào khác để tải dữ liệu không? Có 3 và 4 thậm chí có thể không?

Trả lời

8

Tôi không tin rằng có bất kỳ cách khả thi nào để đạt đượC# 3 hoặC# 4 trong danh sách của bạn.

Trong số các giải pháp khác, bạn liệt kê hai giải pháp có tệp dữ liệu chứa SQL trực tiếp và một có chứa dữ liệu ở định dạng không phải SQL.

Tất cả ba sẽ chỉ hoạt động tốt, nhưng đề xuất sau đó lấy dữ liệu từ một tệp được định dạng và tự xây dựng SQL có vẻ sạch nhất. Nếu khả năng cập nhật hàng loạt thực sự được thêm vào sau này thì tệp dữ liệu của bạn vẫn có thể sử dụng được hoặc ít nhất có thể dễ dàng xử lý thành biểu mẫu có thể sử dụng được. Ngoài ra, việc tạo ra các datafile là đơn giản hơn và ít bị lỗi. Cuối cùng, có dữ liệu "thô" sẽ cho phép nhập vào các định dạng lưu trữ dữ liệu khác.

Trong mọi trường hợp, bạn nên (như bạn đã đề cập) gói các nhóm chèn vào giao dịch để tránh tạo tạp chí giao dịch mỗi hàng.

33

Tôi đã tìm thấy rằng để chèn số lượng lớn, lớp (dường như ít được sử dụng) DatabaseUtils.InsertHelper nhanh hơn vài lần so với sử dụng SQLiteDatabase.insert.

Hai tối ưu hóa khác cũng giúp với hiệu suất ứng dụng của tôi, mặc dù họ có thể không thích hợp trong mọi trường hợp:

  • Đừng bind giá trị mà là rỗng hoặc null.
  • Nếu bạn có thể là nhất định là an toàn để làm điều đó, tạm thời tắt khóa nội bộ của cơ sở dữ liệu cũng có thể giúp hiệu suất.

Tôi có một số blog post để biết thêm chi tiết.

+0

Cảm ơn! Tối ưu hóa này đã tăng nhập một loạt các bản ghi lên gấp 2 lần. –

+0

Tôi đã đọc blog và nhận xét. Cả hai cung cấp chi tiết đủ chèn tất cả dữ liệu của tôi trong vòng một vài giây. Nhiều lần tốt hơn vài phút. – Knossos

+4

Bây giờ 'InsertHelper' không được dùng nữa, chúng ta buộc phải sử dụng' SQLiteStatement'? –

97

Thông thường, mỗi lần sử dụng db.insert(), SQLite tạo một giao dịch (và kết quả là tệp nhật ký trong hệ thống tệp), điều này làm chậm mọi thứ.

Nếu bạn sử dụng db.beginTransaction()db.endTransaction() SQLite chỉ tạo một tệp nhật ký duy nhất trên hệ thống tệp và sau đó cam kết tất cả các lần chèn cùng một lúc, tăng tốc đáng kể mọi thứ.

Dưới đây là một số mã giả từ: 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(); 
} 

Nếu bạn muốn hủy bỏ một giao dịch do một lỗi không mong muốn hoặc một cái gì đó, chỉ cần db.endTransaction() mà không cần đầu tiên thiết lập các giao dịch thành công (db.setTransactionSuccessful()).

Một phương pháp hữu ích khác là sử dụng db.inTransaction() (trả về true hoặc false) để xác định xem bạn có đang ở giữa giao dịch không.

Documentation here

+0

cơ sở dữ liệu bị khóa sau khi thực hiện việc này, cách mở khóa .. – Kishore

+2

Để biết thêm tham chiếu mã: [Chèn hàng loạt vào cơ sở dữ liệu SQLite trên Android] (http://notes.theorbis.net/2010/02/batch-insert-to-sqlite-on-android.html) –

+1

Cố gắng sửa chữa lỗi đánh máy trong 'db.endTransaction()' nhưng nó quá nhỏ chỉnh sửa – acw

9

Vâng, giải pháp của tôi cho nó này loại kỳ lạ nhưng hoạt động tốt ... tôi biên soạn một khoản tiền lớn của dữ liệu và chèn nó trong một đi (số lượng lớn chèn?)

tôi sử dụng các db.execSQL(Query) lệnh và tôi xây dựng "truy vấn" với các tuyên bố sau ...

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

vấn đề duy nhất là việc xây dựng các truy vấn có thể được loại lộn xộn. Tôi hy vọng nó giúp

+0

Cool. Thật là một giải pháp sáng tạo tuyệt vời.Có vẻ như nó sẽ khá nhanh. Là nó? –

+1

Nó sẽ rất nhanh với lớp StringBuilder. –

+0

@Andrew Prat ... Giới hạn tối đa cho UNION là gì. cho tôi bởi hoạt động công đoàn này tôi có thể chèn 500 bản ghi vào một câu lệnh chèn. nếu tôi muốn chèn 5000 bản ghi vào một câu lệnh. nó sẽ có thể? nếu có thì làm thế nào? –

9

Ví dụ này dưới đây sẽ làm việc một cách hoàn hảo

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(); 
Các vấn đề liên quan