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

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

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

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

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

问题

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

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

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


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


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


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


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

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

我使用了伪造的(0或最后一行)行号来强制更新视图,但是问题是如果在选择之前插入/删除了该行,选择之后指向了错误的行,依此类推。

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

这个问题与另一个问题有关:
Display large result set

最佳答案

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

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

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

编辑:

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

10-07 19:33
查看更多