gpt4 book ai didi

performance - VirtualStringTree 正确/推荐使用

转载 作者:行者123 更新时间:2023-12-03 15:18:37 25 4
gpt4 key购买 nike

我使用 virtualstringtree 一段时间了。我将它用于两个不同的用途,首先是一个用于选择、显示数据的普通树,其次是作为一个网格来显示 SQL 语句的输出。

我加载到树中的所有数据都来自数据库。对于树示例,我有一个 ParentId 字段来区分层次结构,对于网格示例,我只需使用 SQL 语句以及每个树的自定义记录(这是唯一的)。

我的问题涉及填充树的首选/最佳方式。我从 VST 文档中了解到,您应该将 onInitNode 事件与 rootnodecount 一起使用。然而,我发现使用 AddChild() 方法非常相似,尽管不鼓励这样做。

让我展示一些(简化的)示例:

<强>1。等级制度

type PData = ^rData;
rData = packed record
ID : Integer;
ParentID : Integer;
Text : WideString;
end;

procedure Loadtree;
var Node : PVirtualNode;
Data : PData;
begin
Q1 := TQuery.Create(Self);
try
Q1.SQL.Add('SELECT * FROM Table');
Q1.Open;
Q1.Filter := 'ParentID = -1'; //to get the root nodes
Q1.Filtered := True;
while not Q1.Eof do
begin
Node := VST.AddChild(nil);
Data := VST.GetNodeData(Node);
Data.ID := Q1.Fields[fldID].AsInteger;
Data.ParentID := Q1.Fields[fldParentID].AsInteger;
Data.Text := Q1.Fields[fldText].AsString;
//now filter the query again to get the children of this node
PopulateChildren(Data.ParentID,Node); //add children to this node and do it recursively
Q1.Next;
end;
finally
Q1.free;
end;

end;

<强>2。网格

procedure LoadGrid;
var Node : PVirtualNode;
Data : PData;
begin
Q1 := TQuery.Create(self);
try
Q1.SQL.Add('SELECT * FROM Table');
Q1.Open;
while not Q1.eof do
begin
Node := VST.AddChild(nil);
Data.ID := Q1.Fields[fldID].AsInteger;
Data.Text := Q1.Fields[fldText].AsString;
Q1.Next;
end;
finally
Q1.Free;
end;
end;

所以本质上我绕过了 RootNodeCount 和 OnInitNode 方法/属性,并使用老式的方法将节点添加到树中。看起来效果很好。请注意,在示例中我在运行时创建和销毁查询。

我开始以这种方式使用树的原因是我可以一次加载树中的所有数据,然后在使用完后释放 TQuery。我在想,无论保持 TQuery 处于事件状态/创建状态,我仍然需要使用我的 rData 记录来存储数据,因此如果我不销毁 TQuery,则会占用更多内存。目前,我的应用程序在完全加载时使用大约 250+MB,并且当我运行 SQL 报告并将其显示在 VST 中时可能会增加。当我运行包含 20000 多个节点和 50 多个列的 SQL 报告时,我发现它使用了大约 1GB 的内存。我想知道我使用 VST 的方式在最小化内存使用方面是否不正确?

创建树的生命周期查询并使用 onInitNode 事件会更好吗?这样,当树请求数据时,它会使用 onInitNode/OnInitChildren 事件从 TQuery 获取数据(即树的纯虚拟范例)?因此,我需要在表单持续时间内保持 TQuery 处于事件状态。以这种方式使用它会有任何内存优势/性能优势吗?

在上述情况下,我可以看到网格示例的差异将远小于层次结构(如果有的话) - 因为所有节点在填充时都需要初始化。

最佳答案

原因AddChild()不鼓励的原因是它打破了组件的虚拟范例 - 您创建所有节点,即使您可能永远不需要它们。假设查询返回 100 条记录,但树当时显示 10 个节点。现在,如果用户从不向下滚动,那么您就浪费了 90 个节点的资源,因为它们永远不需要(不可见)。因此,如果您担心内存使用情况,AddChild()是个坏主意。另一件事是,如果结果集很大,填充树需要时间,并且您的应用程序当时不会响应。当使用虚拟方式( RootNodeCountOnInitNode )时,树立即“准备好”,用户不会遇到任何延迟。

话又说回来,如果使用 AddChild() 得到(相对)小的结果集,可能是最好的选择 - 它允许您在一个简短的事务中加载数据。即,在树结构的情况下,当用户展开父节点时立即加载整个“级别”是有意义的。

将 DB 与 VT 一起使用有点棘手,因为 DB 查询也是特殊资源,有其自身的限制(您希望保持事务简短,它相对较慢,DB 可能只支持单向游标等)。
所以我想说,你必须根据具体情况来决定,具体取决于用例和数据量,即

  • 小型结果集可以使用 AddChild() 一次加载全部内容或进入内部数据结构,然后通过 VT 的事件使用它;
  • 一次加载一层对于树木来说可能是一个很好的折衷方案;
  • 如果结果集非常大,则批量加载可能会带来良好的性能和内存使用妥协,但会增加管理 VT 的代码的复杂性。

关于performance - VirtualStringTree 正确/推荐使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7624319/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com