gpt4 book ai didi

delphi - 如何构建数据库以快速访问节点

转载 作者:IT王子 更新时间:2023-10-29 06:29:34 24 4
gpt4 key购买 nike

我正在寻找一种使用 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() 方法启动节点。欢迎任何想法或指示。

更新(以及我是如何解决的)

这里有一些与 virtualtreeview 无关的信息: Implementing a hierarchical data structure in a database

我最终做的是使用改进的预序树遍历在数据库中存储有关节点的信息,并且每次首先请求某个节点时:

a) 它在内部缓存中查找,它基本上拥有与 VirtualTreeView 结构相同的结构。

b) 如果在缓存中找到,则删除此缓存条目(它永远不会包含超过 100 个项目)

c) 如果未找到,则在缓存中添加额外的 100 个项目(从请求的节点向上 50 个,向下 50 个)。如果需要,当然可以将此数量修改为 500 或 1000 个项目。有一些额外的检查来查看它需要读取多少向上/向下以避免读取过多的重复条目。

d) 如果我需要更快的速度,我可能会应用其他技术 - 根据用户滚动 virtualtreeview 的多少从数据库加载节点 - 类似于 std::vector 分配内存的方式 - 首先我只加载 100 个节点,然后如果用户滚动很多,我加载 200,然后 400 等等......用户滚动越多,它加载整个树的速度就越快,但如果他/她从不滚动,仍然不会加载它。

这样,从未见过的节点永远不会从数据库中加载。它适用于使用鼠标滚轮滚动(当它经过缓存为空且需要更多磁盘数据的点时偶尔会有短暂的延迟)和使用箭头按钮/键滚动。当您将滚动条拖动到某个位置(比如从底部到中间)时,它会有点慢,但这是预料之中的,因为无法立即从磁盘中获取数据。

如果我在加载缓存/项目之前预先确定我要使用多少内存是最好的,滚动越快滚动越快,但如果数据从不显示,它当然会使用更多内存。

最佳答案

不是最优雅的,但这是我用来填充我的树的方法。

只需要两个简单查询的数据访问,其余的都在客户端完成。

它将轻松加载数万个节点。 (现在看,我可能只需要一个查询就可以逃脱 - 它有点旧!):

 procedure TFrameComponentViewer.LoadComponentTree;
var
RootNodeData : PMasterComponent;
CompQ,ParentQ : TMyQuery;

procedure PopulateNodeData(Node: PVirtualNode;ComponentID : integer);
var NodeData : PMasterComponent;
begin
if CompQ.Locate('ComponentID',ComponentID,[loCaseInsensitive]) then
begin
NodeData := TreeComponents.GetNodeData(Node);
//Populate your desired TreeData
NodeData.ComponentID := CompQ.Fields[fldComponentID].AsInteger;
NodeData.ComponentCode := CompQ.Fields[fldComponentCode].AsString;
NodeData.ComponentType := CompQ.Fields[fldComponentType].AsInteger;
NodeData.IsPipeline := CompQ.Fields[fldComponentIsPipeline].AsBoolean;
NodeData.Description := CompQ.Fields[fldComponentDescription].AsString;
NodeData.StartKP := CompQ.Fields[fldComponentStartKP].AsFloat;
NodeData.EndKP := CompQ.Fields[fldComponentEndKP].AsFloat;
NodeData.Diameter := CompQ.Fields[fldComponentDiameter].AsFloat;
NodeData.WallThickness := CompQ.Fields[fldComponentWallThickness].AsFloat;
NodeData.CriticalSpanLength := CompQ.Fields[fldComponentCSL].AsFloat;
NodeData.Historical := CompQ.Fields[fldComponentHistorical].AsBoolean;
end;
end;

procedure AddNodesRecursive(ParentNode : PVirtualNode;ParentNodeID : Integer);
var AddedNode : PVirtualNode;
AddedNodeData : PMasterComponent;
Children : Array of Integer;
i : Integer;
begin
try
ParentQ.Filtered := False;
ParentQ.Filter := 'Parent_ID = '+InttoStr(ParentNodeID);
ParentQ.Filtered := True;
ParentQ.First;
SetLength(Children,ParentQ.RecordCount);
for i:=0 to ParentQ.RecordCount-1 do
begin
Children[i] := ParentQ.Fields[0].AsInteger;
ParentQ.Next;
end;
for i:=0 to High(Children) do
begin
AddedNode := TreeComponents.AddChild(ParentNode);
AddedNodeData := TreeComponents.GetNodeData(AddedNode);
System.Initialize(AddedNodeData^); //initialize memory
PopulateNodeData(AddedNode,Children[i],CompQ);
AddNodesRecursive(AddedNode,AddedNodeData.ComponentID);
end;
finally
end;
end;

begin
TreeComponents.BeginUpdate;
treeComponents.Clear;
CompQ := TMyQuery.Create(nil);
ParentQ := TMyQuery.Create(nil);
try
CompQ.Connection := DataBaseline.BaseLineConnection;
CompQ.SQL.Add('SELECT * FROM Components');
CompQ.Open;
ParentQ.Connection := DataBaseline.BaseLineConnection;
ParentQ.Close;
ParentQ.SQL.Clear;
ParentQ.SQL.Add('SELECT ComponentID,Parent_ID FROM Components ORDER BY OrderNo');
ParentQ.Open;
RootNode := TreeComponents.AddChild(nil);
RootNodeData := TreeComponents.GetNodeData(RootNode);
System.Initialize(RootNodeData^); //initialize memory
RootNodeData.ComponentID := -1;
AddNodesRecursive(RootNode,-1);
finally
TreeComponents.EndUpdate;
TreeComponents.FullExpand;
CompQ.Close;
ParentQ.Close;
FreeandNil(CompQ);
FreeandNil(ParentQ);
end;
end;

注意:OrderBy 列是可选的,我需要它,因为我的树是特定于顺序的。

因此数据库具有这三列,以及您需要的任何自定义数据:

IDParentID(-1 表示没有父级)、OrderNo

关于delphi - 如何构建数据库以快速访问节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8553214/

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