2

我有一个包含大量日志消息的 SQLite 数据库。

我想在列表视图中显示它(使用 wxWidgets)。

用户可以重新排序列表(通过按下列标题),对结果集应用过滤器,并使用滚动条像通常的列表一样浏览它。用户还可以选择列表中的一个或多个条目并删除它们。

我有一个虚拟列表模型:列表视图向模型询问特定行的内容。该模型使用当前过滤条件和顺序发出选择查询,并从结果中返回相应的行。

为了让它更快,我保留了结果的页面缓存:当请求一行时,我使用 LIMIT 和 OFFSET 获取整个页面(约 100 行)并从页面返回特定行。我存储了许多页面,下次请求一行时,我首先查看它是否在其中一个缓存页面中可用。事实证明,即使有很多条目(50k+),这种技术也能快速响应。

问题

我的问题是如何处理更新/插入/删除。我每个都有一个触发器,因此每当发生插入/更新/删除时都会通知模型。触发器还告诉模型受影响条目的 ID(主键)。

我的第一个版本只是在每次触发后对模型进行了完全重置。这不是很快,但足够快。问题是,如果用户选择了一行或几行,选择就会丢失。

模型的基类 (wxDataViewVirtualListModel) 包含在发生更改时应调用的方法:

  • RowInserted(行)
  • 行已删除(行)
  • RowChanged(行)

如果我使用它们,选择问题将得到解决,但是存在问题:

  • 我如何知道更改的行是否在当前过滤集中?
  • 我如何知道列表视图中的哪一行受到了影响?

第一个问题可以通过创建一个检查条目是否属于集合的方法来解决。它的行为必须与 SQL 条件完全相同,但它是可行的。

第二个问题我根本不知道如何解决。

我使用了一个虚假的(0 或最后一行)行号来强制更新视图,但问题是如果在选择之前插入/删除了行,则选择之后指向错误的行,等等。

你会怎么做?在内存中保留包含所有条目的高级数据结构?

这个问题与另一个问题有关: 显示大结果集

4

1 回答 1

1

我将围绕两个不同的 SELECT 操作进行设计,一个只获取所有行的主键和时间戳(INSERT / UPDATE),另一个获取单页行的所有数据。在现代机器上,即使是 100000 行,在内存中保留完整的主键和时间戳列表也不应该成为问题。

每当过滤条件更改或触发器触发时,我都会再次检索主键和时间戳列表。该模型维护一个主键列表和匹配时间戳,模型与新列表之间的比较显示需要插入、无效或删除哪些行。时间戳已更改的缓存行将从缓存中删除,具有相同时间戳的缓存行无需再次检索。当缓存变得太大时,将删除最旧的缓存条目。

列表的选择可以通过其主键值来识别,因此除非该行已被删除,否则始终可以在更改模型后重新选择它,即使它现在处于完全不同的位置。我发现这比在排序更改时保持相同的行位置更直观,因为它选择了完全不同的行。

编辑:

这适用于来自其他数据库客户端的并发数据更改,我已经为使用 Firebird 数据库服务器的应用程序实现了这种方式。如果无法从外部更改数据,则可能不需要始终检索主键和时间戳的完整列表。

于 2009-05-08T11:18:47.490 回答