2009-09-10 19 views
18

SQLite veritabanlarında yüzlerce megabaytlık HTML'ye sahip bir istemci için bir uygulama oluşturuyoruz. Bu verileri sorgulamak ve tüm bunları makul bir şekilde hızlı bir şekilde taramak için bir yöntem geliştirdik. Sorun, veritabanlarının bazılarının çok büyük sorgulara (20.000'den fazla satır) sahip olması ve kullanıcı ilerledikçe sorguları büyüttüğümüzde hatalar görüyor olmasıdır. Bu yüzden, soru şu ki, Android'de on binlerce veri satırını sorgulamada ve göstermede hangi seçeneklere sahibiz? İşte Android SQLite ve büyük veri setleri

09-10 19:19:12.575: WARN/IInputConnectionWrapper(640): showStatusIcon on inactive InputConnection 
09-10 19:19:18.226: DEBUG/dalvikvm(640): GC freed 446 objects/16784 bytes in 330ms 
09-10 19:19:32.886: ERROR/CursorWindow(19416): need to grow: mSize = 1048576, size = 36, freeSpace() = 30, numRows = 17717 
09-10 19:19:32.896: ERROR/CursorWindow(19416): not growing since there are already 17717 row(s), max size 1048576 
09-10 19:19:32.916: ERROR/CursorWindow(19416): The row failed, so back out the new row accounting from allocRowSlot 17716 
09-10 19:19:33.005: ERROR/Cursor(19416): Failed allocating fieldDir at startPos 0 row 17716 
09-10 19:19:35.596: DEBUG/Cursor(19416): finish_program_and_get_row_count row 24315 
09-10 19:19:41.545: DEBUG/dalvikvm(698): GC freed 2288 objects/126080 bytes in 260ms 
09-10 19:19:43.705: WARN/KeyCharacterMap(19416): No keyboard for id 0 
09-10 19:19:43.717: WARN/KeyCharacterMap(19416): Using default keymap: /system/usr/keychars/qwerty.kcm.bin 
09-10 19:20:04.705: ERROR/CursorWindow(19416): need to grow: mSize = 1048576, size = 17, freeSpace() = 3, numRows = 17094 
09-10 19:20:04.716: ERROR/CursorWindow(19416): not growing since there are already 17094 row(s), max size 1048576 
09-10 19:20:04.726: ERROR/Cursor(19416): Failed allocating 17 bytes for text/blob at 17093,2 
09-10 19:20:05.656: DEBUG/Cursor(19416): finish_program_and_get_row_count row 5257 
09-10 19:24:54.685: DEBUG/dalvikvm(637): GC freed 9297 objects/524176 bytes in 247ms 
09-10 19:32:07.656: DEBUG/dalvikvm(19416): GC freed 9035 objects/495840 bytes in 199ms 

bizim CursorAdapter kodudur: Burada

Gördüğümüz StackTrace olan onbinlerce sorgulanması ve görüntülenmesinde Elimizdeki ne seçenekler

private class MyAdapter extends ResourceCursorAdapter { 

    public MyAdapter(Context context, Cursor cursor) { 
     super(context, R.layout.my_row, cursor);   
    } 

    public void bindView(View view, Context context, Cursor cursor) {     
     RowData data = new RowData(); 
     data.setName(cursor.getInt(cursor.getColumnIndex("name"))); 

     TextView tvItemText = (TextView)view.findViewById(R.id.tvItemText); 
     tvItemText.setText(data.getName()); 

     view.setTag(data); 
    } 

    @Override 
    public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 
     /* Display the progress indicator */ 
     updateHandler.post(onFilterStart); 

     /* Run the actual query */    
     if (constraint == null) { 
      return myDbObject.getData(null);      
     } 

     return myDbObject.getData(constraint.toString());     
    }    
} 
+0

"Android'de binlerce satırlık veriyi sorgulamada ve görüntülemede hangi seçeneklere sahibiz?" -> eh? Bunu neden yapmak isteyebileceğini bile düşünemiyorum. – SK9

+0

@ SK9 Bu, iPhone'dan Android'e bir tıbbi referans uygulaması taşımak içindi. Bu SQLite veritabanlarında tam anlamıyla on binlerce kayıt vardı. Herhangi bir aklı başında, listeyi daraltmak için bir arama terimi girmeye başlayacaktı, ancak iPhone uygulaması, tüm verileri mükemmel bir şekilde manuel olarak kaydırmayı destekledi. Böylece Android uygulamasının da aynı şekilde davranmasını beklediler. – MattC

+0

Benzer bir gereksinim var. Bu şekilde kaç tane kuruluşun özel uygulamaları kullandığı şaşıracaktı. – gonzobrains

cevap

26

Android'deki veri satırları

Bir 3.5" LCD üzerinde 20.000'den fazla satır okuma söylüyorum dışında mı çılgın sopası martı gübresi nedir? ;-) Bu kapakların altında bir yerlerde kullanılır CursorWindow benziyor

sahip konulardır yönetme> 17.000 satır yani iki şeyden biri olabilir:.

  1. Sen yığın alanı dışında 16MB olmayan sıkışan yığın ve Cursor yığın ayarlanan tüm sonuç tutan gerçeği ile, o. sorudan çıkmadı
  2. CursorWindow sadece 1 MB veriyi destekler, hata mesajının daha doğrudan önerdiği şey budur. ayrık parçalar halinde sorguları bölmek için mantıklı bir yolu varsa

, artımlı sorguları yapmak ve bunları birleştirmek için CursorJoiner kullanın ve eğer yardımcı olur görebiliyordu.

Ama bütün ciddiyetiyle, en yakın beygir gücü yaşamını kaybeden 12 yaşındaki PC benzer bir cihaz üzerinde 3.5" ekranda 20.000'den fazla satır, gerçekten çok istiyor.

+0

Ne yazık ki, iPhone üzerinde bir çekicilik gibi çalışıyor ve müşteri karşılaştırılabilir performans bekliyor. Bu örnekte, sadece kırılma düzleşiyor ve bu tamamen kötü. Bir seferde birkaç satır yüklemek için sorguyu kırıyoruz. Mesele, dibe indiğinde ve listenin en altına inmeyi bekledikleri zamandır. – MattC

+3

* silkmek * Sorgu sonuçlarınızı 1MB'ın altında tutmak için bir yol bulun. Daha az sütun isteyin. Verilerinizi daha iyi bir şekilde toplayın (ör., Her bir Boole değeri için 8 INTEGER sütunu kullanmayın - bir INTEGER sütunu ve bit maskesini kullanın). Kullanıcının sürekli olarak daha iyi filtrelemesine olanak tanıyan bir UX ile gelin, böylece bir 20K satır sonuç kümesine girmeyeceksiniz. Bir CursorWindow kullanarak SQLiteCursor/SQLiteQuery etrafında çalışmayı deneyebilirsiniz, ancak performansınızın kötü olacağından şüpheleniyorum. – CommonsWare

+0

Sanırım 42.000 ürün içeren bir tablonuz olduğunda ve bir seferde 30-40 yüklediğinizde, bir listeyi kolayca kaydırmanın en iyi yolunun ne olduğunu merak ediyorum. Daha küçük tablolar için çalışır, ancak bu belirli veritabanı için sorgudaki LIMIT ve OFFSET kullanımı hala kaydırmada ANR ve hıçkırıklara neden olur. – MattC

5

Eğer gerçekten gerekiyorsa ayrıca veri bölme ve bunun gibi parçalar okuyabileceği. Bu 5k satırlar için 2 sn altında çalışıyor

int limit = 0; 
    while (limit + 100 < numberOfRows) { 
     //Compose the statement 
     String statement = "SELECT * FROM Table ORDER someField LIMIT '"+ limit+"', 100"; 
     //Execute the query 
     Cursor cursor = myDataBase.rawQuery(statement, null); 
     while (cursor.moveToNext()) { 
      Product product = new Product(); 
      product.setAllValuesFromCursor(cursor); 
      productsArrayList.add(product); 
     } 
     cursor.close(); 
     limit += 100; 
} 

//Compose the statement 
String statement = "SELECT * FROM Table ORDER someField LIMIT '"+ (numberOfRows - limit)+"', 100"; 
//Execute the query 
Cursor cursor = myDataBase.rawQuery(statement, null); 

while (cursor.moveToNext()) { 
    Product product = new Product(); 
    product.setAllValuesFromCursor(cursor); 
    productsArrayList.add(product); 
} 
cursor.close(); 

dizine varsa tablo

Teşekkür, Arkde

0

Tecrübemde, sorguları sınırlamak, sonuçların elde edilmesini çok daha uzun sürer çünkü yeni imleçlerin başlatılması düşük sınırlar için pahalıdır. Ben şimdi 1k ve hatta 10k sınırı ile 62k satırları yapmaya çalıştım ve 6'dan fazla imleci başlatmak zorundayım çünkü çok yavaş ve kullanılamaz. Ben sadece 2.3.3 desteklemeyen birşeyler yapacağız .... En son yapı, WARN yerine CursorWindow ERROR.

Yaptığım şey buydu. Bu muhtemelen bence en iyi algoritmadır. İki kez vb. Sorgular yapmak zorunda değilsiniz. Ancak, büyük sorgularla ve küçük sınırlarla oldukça yavaş olabilir, bu yüzden en çok neyin işe yaradığını test etmeniz gerekir. Benim durumumda, 62k satırlarını iyi idare etmediği için amaçlarınız için yeterince hızlı değil.

int cursorCount = 0; 
int limit = 1000; //whatever you want 
while (true) 
{ 
    Cursor cursor = builder.query(mDatabaseHelper.getReadableDatabase(), columns, selection, selectionArgs, null, null, null, Integer.toString(limit)); 
    if (cursor == null) { 
     return null; 
    } else if (!cursor.moveToFirst()) { //if it is empty, return null 
     return null; 
    } 
    cursorCount = cursor.getCount(); 
    if (cursorCount % limit != 0) 
    { 
     return cursor; 
    } 
    limit+=1000; //same amount as the one above 
}