游标窗口无法容纳过大的行,需要位置为0,总行数为1;

4

我一直收到这个烦人的提示信息!

当数据插入本地数据库完成后,我看到了这条消息。

JNI critical lock held for 30.083ms on Thread[27,tid=23883,Runnable,Thread*=0xce150a00,peer=0x12cc0190,"Sqflite"]

如果我从表中选择数据,我会得到

W/CursorWindow(23809): Window is full: requested allocation 3095146 bytes, free space 2096696 bytes, window size 2097152 bytes
E/SQLiteQuery(23809): exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT * FROM description_table;
I/flutter (23809): DatabaseException(Row too big to fit into CursorWindow requiredPos=0, totalRows=1) sql 'SELECT * FROM defect_description_table;' args []}

我没有任何二进制大对象数据,全部都是字符串。那么为什么会发生这种情况呢?

以下是 JSON 结构

[{ "id": 1, "name": "Descriptions","data": [{..},{...} ... ]},{....},{....}]

我认为问题出在数据列表上,因为它包含了很多数据(共10298个)?

这个问题应该怎么解决?

我的插入方法:

Future insertData(
      BuildContext context, String urls, String accessToken) async {
    CategoryTableData categoryData = CategoryTableData();
    try {
      var desc = List<Desc>();
      var headers = {
        'authorization': "Bearer" + " " + accessToken,
        "Accept": "application/json"
      };
      var url = xxx;
      var response = await http.get(url, headers: headers);
      var res = json.decode(response.body);
      for (var i in res) {
        if (i['name'] == "Descriptions") {
          desc.add(Desc(
              id: i['id'], name: i['name'], data: i['data']));
        }
      }
      await dao.batch((b) {
        b.insertAll(_dao.descTable, desc);
      });
      categoryData = await _dao.selectAllCategories();
      return categoryData;
    } catch (e) {
      print(e);
      categoryData = await _dao.selectAllCategories();
      return categoryData;
    }
  }

描述

class Desc extends Table {
  IntColumn get id => integer().nullable()();
  TextColumn get name => text().named("name").nullable()();
  TextColumn get data => text().map(const ListConverter()).nullable()();
}
2个回答

5

这条信息 Window is full: requested allocation 3095146 bytes, free space 2096696 bytes, window size 2097152 bytes

告诉您正在尝试将大小为3095146字节的行(* =所有列)放入一个缓冲区中,该缓冲区有2096696字节的空闲空间,可用字节数为2097152(2Mb)。

简而言之,数据量过大,无法提取数据。当插入数据时,由于没有中介和相对有限的缓冲区(光标窗口),因此这不是问题。

通常在尝试检索存储的图像时会看到此情况。

有各种方法可用于规避此问题。

  • 对于这么大的行,你可以将实际数据存储为文件,并在数据库中存储文件路径(这对于图像是推荐的)。

  • 如果提取列的数量较少,则可以尝试减少提取的列。即不使用SELECT *,而是只指定所需的列。

  • 如果列数据的累积大小是问题所在,则可以使用多个if提取多个部分。

    • 您可以使用length(column_name)函数选择数据部分,可能需要使用CASE WHEN THEN ELSE END表达式/构造,然后在检索到数据时构建完整数据。

    • 可能是您无意中存储了更多的数据,例如在循环中意外地连接数据。

您需要了解存储的数据以知道上述哪些方法可能有用。


1
问题在于您正在使用 selectAllCategories() 方法检索过多的数据,该方法在 insertData 中被调用。处理与 sqlite 的连接的本机插件实现是导致错误的原因。您应该使用纯 SQL 限制查询,例如:
SELECT * FROM defect_description_table limit 500;

如果您正在使用Moor或其他生成此代码的包,请查阅其有关限制查询的文档。

2
问题不在于行数,而在于每行的大小。游标窗口是一个缓冲区/缓存,它将保存x行数据。如果无法保存1行数据,则会出现上述问题。 - MikeT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接