SQLite 闭包 table 实现的性能问题
Performance issue on SQLite closure table implementation
首先我要说的是,我对 SQL 和数据库系统还很陌生,所以请原谅我可能犯的任何新手错误。
我正在使用闭包 table 在 SQLite 数据库中插入分层数据。我正在为 SQLite 版本 3.26.0 使用 C# (.NET 4.6.1) 和 SQLite 预编译的 32 位 DLL (x86)。插入的分层数据包含~240000个元素,最大树深度不大于7.
我的分层元素 table 是:
CREATE TABLE element (elementId INTEGER PRIMARY KEY, parentId INTEGER, elementName TEXT, FOREIGN KEY (parentId) REFERENCES element(elementId));
我的闭包 table 定义为:
CREATE TABLE hierarchy (parentId INTEGER, childId INTEGER, depth INTEGER, FOREIGN KEY(parentId) REFERENCES element(elementId), FOREIGN KEY(childId) REFERENCES element(elementId));
使用经典堆栈插入元素,该堆栈从“根”元素开始,在处理内部事务期间使用以下方式将元素的成员添加到该元素:
INSERT INTO element VALUES (<ELEMENT_ID>, <PARENT_ID>'<ELEMENT_NAME');
我用“self”关系初始化闭包table,使用:
INSERT INTO hierarchy(parentId, childId, depth) VALUES (<ELEMENT_ID>, <ELEMENT_ID>, 0);
这些插入不会导致任何问题,只需几秒钟即可执行。
接下来,我使用相同的堆栈方法再次遍历所有元素以构建闭包 table(注意:我可能会在前面的说明的同时执行此操作,但我是在一个单独的循环来隔离性能问题)使用以下代码(在另一个事务中):
INSERT INTO hierarchy SELECT p.parentId, c.childId, p.depth+c.depth+1 FROM hierarchy p, hierarchy c WHERE p.childId=<PARENT_ID> AND c.parentId=<ELEMENT_ID>;
但是,此查询需要数小时,甚至数天才能执行。它的执行时间也越来越长。我知道它在闭包 table 中插入了很多元素(当前元素及其所有上升项之间的每个关系一个条目),但我想知道是否可以做些什么来提高这里的性能?
谢谢
您需要子键和父键的索引。还将所有内容包装在一个事务中。
更好的是,使用单个递归 CTE 生成闭包 table,类似
with recursive
closure as (
select elementId, elementId as parentId, 0 as depth from element
union all
select closure.elementId, element.parentId, 1 + depth as depth
from closure, element where closure.parentId = element.elementId
)
select * from closure
要实际创建 table,请使用类似 create table hierarchy as
的方法将上述结果放入 table。
首先我要说的是,我对 SQL 和数据库系统还很陌生,所以请原谅我可能犯的任何新手错误。
我正在使用闭包 table 在 SQLite 数据库中插入分层数据。我正在为 SQLite 版本 3.26.0 使用 C# (.NET 4.6.1) 和 SQLite 预编译的 32 位 DLL (x86)。插入的分层数据包含~240000个元素,最大树深度不大于7.
我的分层元素 table 是:
CREATE TABLE element (elementId INTEGER PRIMARY KEY, parentId INTEGER, elementName TEXT, FOREIGN KEY (parentId) REFERENCES element(elementId));
我的闭包 table 定义为:
CREATE TABLE hierarchy (parentId INTEGER, childId INTEGER, depth INTEGER, FOREIGN KEY(parentId) REFERENCES element(elementId), FOREIGN KEY(childId) REFERENCES element(elementId));
使用经典堆栈插入元素,该堆栈从“根”元素开始,在处理内部事务期间使用以下方式将元素的成员添加到该元素:
INSERT INTO element VALUES (<ELEMENT_ID>, <PARENT_ID>'<ELEMENT_NAME');
我用“self”关系初始化闭包table,使用:
INSERT INTO hierarchy(parentId, childId, depth) VALUES (<ELEMENT_ID>, <ELEMENT_ID>, 0);
这些插入不会导致任何问题,只需几秒钟即可执行。
接下来,我使用相同的堆栈方法再次遍历所有元素以构建闭包 table(注意:我可能会在前面的说明的同时执行此操作,但我是在一个单独的循环来隔离性能问题)使用以下代码(在另一个事务中):
INSERT INTO hierarchy SELECT p.parentId, c.childId, p.depth+c.depth+1 FROM hierarchy p, hierarchy c WHERE p.childId=<PARENT_ID> AND c.parentId=<ELEMENT_ID>;
但是,此查询需要数小时,甚至数天才能执行。它的执行时间也越来越长。我知道它在闭包 table 中插入了很多元素(当前元素及其所有上升项之间的每个关系一个条目),但我想知道是否可以做些什么来提高这里的性能?
谢谢
您需要子键和父键的索引。还将所有内容包装在一个事务中。
更好的是,使用单个递归 CTE 生成闭包 table,类似
with recursive
closure as (
select elementId, elementId as parentId, 0 as depth from element
union all
select closure.elementId, element.parentId, 1 + depth as depth
from closure, element where closure.parentId = element.elementId
)
select * from closure
要实际创建 table,请使用类似 create table hierarchy as
的方法将上述结果放入 table。