mirror of
https://gitcode.com/JianFeeeee/TrulyMEM-TrueHumanMEM.git
synced 2026-10-15 12:15:32 +00:00
perf: removeOrphanNodes O(N²) → O(N) 批量查询优化
- 改为先批量查询所有 active 关系的节点 ID 集合 - 再遍历所有节点找出孤儿节点 - 从 O(N×2) 查询降到 O(1) 批量 + O(N) 遍历 - 显著提升 cleanup / purge 性能
This commit is contained in:
@ -576,34 +576,36 @@ export class GraphDatabase {
|
|||||||
private async removeOrphanNodes(): Promise<number> {
|
private async removeOrphanNodes(): Promise<number> {
|
||||||
if (!this.store) return 0;
|
if (!this.store) return 0;
|
||||||
let deleted = 0;
|
let deleted = 0;
|
||||||
const predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('nodes');
|
// 优化:批量查询所有有关系的节点 ID,避免 O(N²) 逐节点检查
|
||||||
const resultSet: relationalStore.ResultSet = await this.store.query(predicates, ['id', 'name']);
|
const activeRelPred: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('relations');
|
||||||
const nodesToCheck: number[] = [];
|
activeRelPred.equalTo('status', 'active');
|
||||||
while (resultSet.goToNextRow()) {
|
const relResultSet: relationalStore.ResultSet = await this.store.query(activeRelPred, ['subject_id', 'object_id']);
|
||||||
nodesToCheck.push(resultSet.getLong(resultSet.getColumnIndex('id')));
|
const relatedIds = new Set<number>();
|
||||||
|
while (relResultSet.goToNextRow()) {
|
||||||
|
relatedIds.add(relResultSet.getLong(relResultSet.getColumnIndex('subject_id')));
|
||||||
|
relatedIds.add(relResultSet.getLong(relResultSet.getColumnIndex('object_id')));
|
||||||
}
|
}
|
||||||
resultSet.close();
|
relResultSet.close();
|
||||||
|
|
||||||
for (const nodeId of nodesToCheck) {
|
// 查询所有节点,筛选出不在关系中的孤儿节点
|
||||||
const pred1: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('relations');
|
const nodePred: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('nodes');
|
||||||
pred1.equalTo('subject_id', nodeId);
|
const nodeResultSet: relationalStore.ResultSet = await this.store.query(nodePred, ['id']);
|
||||||
const rs1 = await this.store.query(pred1, ['id']);
|
const orphanIds: number[] = [];
|
||||||
const hasSourceRel = rs1.goToFirstRow();
|
while (nodeResultSet.goToNextRow()) {
|
||||||
rs1.close();
|
const nodeId = nodeResultSet.getLong(nodeResultSet.getColumnIndex('id'));
|
||||||
|
if (!relatedIds.has(nodeId)) {
|
||||||
const pred2: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('relations');
|
orphanIds.push(nodeId);
|
||||||
pred2.equalTo('object_id', nodeId);
|
|
||||||
const rs2 = await this.store.query(pred2, ['id']);
|
|
||||||
const hasTargetRel = rs2.goToFirstRow();
|
|
||||||
rs2.close();
|
|
||||||
|
|
||||||
if (!hasSourceRel && !hasTargetRel) {
|
|
||||||
const deletePred: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('nodes');
|
|
||||||
deletePred.equalTo('id', nodeId);
|
|
||||||
await this.store.delete(deletePred);
|
|
||||||
deleted++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nodeResultSet.close();
|
||||||
|
|
||||||
|
// 批量删除孤儿节点
|
||||||
|
for (const orphanId of orphanIds) {
|
||||||
|
const deletePred: relationalStore.RdbPredicates = new relationalStore.RdbPredicates('nodes');
|
||||||
|
deletePred.equalTo('id', orphanId);
|
||||||
|
await this.store.delete(deletePred);
|
||||||
|
deleted++;
|
||||||
|
}
|
||||||
return deleted;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user