【发布时间】:2012-01-23 02:29:59
【问题描述】:
我正在寻找一种方法来构建具有 VirtualTreeView 和 SQLite 数据库的数据库,以便快速检索数据。 VirtualTreeView 有一个 OnNodeInit 事件,但它并不总是适用于此目的。
数据是从 Usenet 新闻组获取的,需要线程化。对线程有用的数据是帖子 id(int64,也是主键)、引用(引用线程中以前帖子的字符串)。
程序在引用中搜索字符串并确定它应该在哪个 postid 下。比如post id = 1234,那么下一个post可能是1235,那么1236可能是回复1234。
这是一个可能的数据库示例:
post id references parent id
1234 .... .... 0
1235 .... .... 0
1236 .... .... 1234
所以现在这就是它现在的样子。
现在,问题是如何构建这些数据以加快检索速度。如果只有一个根节点,我可以根据数据库条目分配 RootNodeCount,然后在 OnNodeInit 中按要求一一读取。当有子节点时,我需要以某种方式重新排列数据库,以便它知道如何根据打开的节点更快地获取子节点。
我正在考虑为附加字段“has_subnodes”分配以下子节点的 ID。当单击一个节点时,它会读取该节点和每个链接的节点。
你将如何组织这个数据库以便它可以在 OnNodeInit 中很好地读取,或者你会使用那个事件吗?节点也可以使用 AddChildNoInit() 方法启动。欢迎任何想法或指示。
更新(以及我是如何解决的)
这里有一些与虚拟树视图无关的信息: Implementing a hierarchical data structure in a database
我最终做的是使用 Modified Preorder Tree Traversal 将有关节点的信息存储在数据库中,并且每次首先请求某个节点时:
a) 它在内部缓存中查找,该缓存基本上与 VirtualTreeView 结构具有相同的结构。
b) 如果在缓存中找到,则删除此缓存条目(它永远不会超过 100 项)
c) 如果未找到,则在缓存中添加额外的 100 项(请求节点向上 50 项,向下 50 项)。如果需要,当然可以将此数量修改为 500 或 1000 个项目。有一些额外的检查来查看它需要读取多少向上/向下以避免读取过多的重复条目。
d) 如果我需要更快的速度,我可能会应用额外的技术 - 根据用户滚动 virtualtreeview 的数量从数据库加载节点 - 类似于 std::vector 分配内存的方式 - 首先我只加载 100 个节点,然后如果用户滚动很多,我加载 200,然后 400 等等......用户滚动越多,加载整个树的速度越快,但如果他/她从不滚动,仍然不会加载它。
这样,从未见过的节点永远不会从数据库中加载。它适用于使用鼠标滚轮滚动(当它通过缓存为空且需要来自磁盘的更多数据的点时偶尔会有短暂的延迟)和使用箭头按钮/键滚动。当您将滚动条拖动到某个位置(例如从底部到中间)时,速度会稍慢一些,但这是意料之中的,因为无法立即从磁盘获取数据。
最好在加载缓存/项目之前预先确定要为缓存/项目使用多少内存,滚动越快越快,但如果数据从不显示,它当然会使用更多内存。
【问题讨论】:
-
家长。您需要家长参考
-
基本上,最简单的树状数据有
ID和ParentID,其中ParentID 指向它作为孩子所属的ID。将子节点放在适当的父节点下(以最简单的形式)需要遍历所有现有节点,直到找到一个 ID 等于 ParentID 的节点。尽管遍历所有 VirtualTreeView 节点非常快,但随着添加更多节点,它可能会变得非常慢。一种更快的方法是将所有节点添加为平面列表,然后将它们移动到适当的位置,尽管算法可能会更复杂一些。 -
@LightBulb 但是我失去了树的虚拟性并且不动态添加它们?如果节点和子节点很多,还没有打开的不需要添加吗?
-
我想我在这里找到了一些有用的东西,这不是一个严格的 virtualtreeview 问题:stackoverflow.com/questions/544632/…
-
VirtualTreeView 可以处理数十万个节点而不会造成任何性能损失,即使是一百万个节点也不算多。我建议您先尝试几种不同的方法,然后再选择一种可以解决您的问题的方法。我建议的只是一个基本想法,未经测试,但如果实施得当,应该可以工作。当然,还有更好的算法。我只是给了你基本的想法。如果我有时间,我会自己进行模拟,如果我发现更适合您的情况,我会在此处发布。
标签: delphi sqlite c++builder hierarchical-data virtualtreeview