Android的SQLite和巨大的数据集

我们正在为SQLite数据库中的数百兆字节的HTML客户端创build一个应用程序。 我们已经实现了一种查询这些数据的方式,并以相当快的速度滚动浏览这些数据。 问题是一些数据库有非常大的查询(20,000多行),当用户滚动查询时,我们正在查看错误。 所以我想问题是,在Android中查询和显示成千上万行数据有哪些select?

这里是我们看到的堆栈跟踪:

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 

这是我们的CursorAdapter代码:

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

在Android中查询和显示成千上万行数据有哪些select?

你的意思是,除了告诉你,阅读3.5“液晶显示器上的20,000多行是蝙蝠鸟疯了吗?;-)

它看起来像是CursorWindow ,在封面下面的某个地方使用,在pipe理> 17000行时遇到了问题。 这可能是两件事之一:

  1. 你没有堆空间。 有了一个16MB的非压缩堆,而且一个Cursor在堆中保存了整个结果集的事实,这是不成问题的。
  2. CursorWindow只支持1MB的数据,这就是错误信息更直接的build议。

如果有一种合理的方法来将你的查询分成不连续的块,你可以做增量查询并使用CursorJoiner将它们拼接在一起,看看是否有帮助。

但是,严肃地说,在3.5英寸屏幕上的2万多行,与一台12年前的电脑最相似的设备,真的是要求很高。

如果你真的需要,你也可以拆分你的数据,并阅读块:

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

如果你有索引表,它在5k行下工作2s。

谢谢,Arkde

根据我的经验,限制查询使得获取结果花费更多的时间,因为启动新的游标对于低限制是昂贵的。 我试着做了62k行,1k甚至10k的限制,因为我必须启动6个以上的游标,所以速度非常慢,无法使用。 我只是坚持不支持2.3.3 ….这是我得到CursorWindow错误而不是WARN的最新版本。

这是我做的。 这可能是我认为最好的algorithm。 不需要重复查询两次。但是,如果查询次数较多,而且限制较小,则可能会变得非常缓慢,因此您必须testing哪种方法效果最好。 就我而言,由于不能很好地处理62k行,所以对我的目的来说还不够快。

 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 }