我正在寻找一种使用 VirtualTreeView 和 SQLite 数据库来构建数据库以快速检索数据的方法。使用 VirtualTreeView 有一个 OnNodeInit 事件,但它并不总是适用于此目的。
数据是从 Usenet 新闻组中获取的,需要进行线程化。对线程有用的数据是帖子 id(int64,也是主键)、引用(引用线程中以前帖子的字符串)。
该程序在引用中搜索字符串并确定它应该在哪个 postid 下。因此,例如帖子 id = 1234,那么下一个帖子可能是 1235,然后 1236 可能是对 1234 的回复。
这是一个可能的数据库示例:
post id references parent id
1234 .... .... 0
1235 .... .... 0
1236 .... .... 1234
所以现在这就是它现在的样子。
现在,问题是如何构建这些数据以加快检索速度。如果只有一个根节点,我可以根据数据库条目分配 RootNodeCount,然后在 OnNodeInit 中按要求一一读取。当有子节点时,我需要以某种方式重新排列数据库,以便它知道如何根据打开的节点更快地获取子节点。
我正在考虑为附加字段“has_subnodes”分配随后的子节点ID。单击一个节点时,它会读取该节点和每个链接的节点。
你将如何组织这个数据库以便它可以在 OnNodeInit 中很好地读取,或者你会使用那个事件吗?节点也可以使用 AddChildNoInit() 方法启动。欢迎任何想法或指示。
更新(以及我是如何解决的)
这里有一些与虚拟树视图无关的信息: 在数据库中实现分层数据结构
我最终做的是使用 Modified Preorder Tree Traversal 将有关节点的信息存储在数据库中,并且每次首先请求某个节点时:
a) 它在内部缓存中查找,该缓存基本上与 VirtualTreeView 结构具有相同的结构。
b) 如果在缓存中找到,则删除此缓存条目(它永远不会超过 100 个项目)
c) 如果没有找到,额外的 100 个项目被添加到缓存中(从请求的节点向上 50,向下 50)。如果需要,当然可以将此数量修改为 500 或 1000 个项目。有一些额外的检查来查看它需要读取多少向上/向下以避免读取过多的重复条目。
d)如果我需要更快的速度,我可以应用额外的技术——根据用户滚动 virtualtreeview 的多少从数据库加载节点——类似于 std::vector 分配内存的方式——首先我只加载 100 个节点,然后如果用户滚动很多,我加载 200,然后 400 等等......用户滚动的越多,加载整个树的速度越快,但如果他/她从不滚动,仍然不会加载它。
这样,从未见过的节点永远不会从数据库中加载。它适用于使用鼠标滚轮滚动(当它通过缓存为空且需要来自磁盘的更多数据的点时偶尔会有短暂的延迟)和使用箭头按钮/键滚动。当您将滚动条拖动到某个位置(例如从底部到中间)时,速度会稍慢一些,但这是意料之中的,因为无法立即从磁盘获取数据。
最好在加载缓存/项目之前预先确定要为缓存/项目使用多少内存,滚动速度越快,但如果数据从未显示,它当然会使用更多内存。