【发布时间】:2026-01-22 17:50:01
【问题描述】:
我的情况是,我目前正在将一个层次结构存储在一个快速接近 15000 个节点(5000 个边)的 SQL 数据库中。此层次结构根据用户在树中的位置定义我的安全模型,授予对以下项目的访问权限。因此,当用户请求所有受保护项目的列表时,我使用 CTE 在 db 中对其进行递归(并展平所有项目),这开始显示其年龄(慢)。
层次结构不会经常变化,所以我尝试将其移入 RAM ( redis )。请记住,我有许多子系统需要它来进行安全调用,并且 UI 需要为 CRUD 操作构建树。
第一次尝试
我的第一次尝试是将关系存储为键值对 (这就是它在数据库中的存储方式)
乙 / \ F G / \ / \ 嗨JK 映射到: E - [F, G] F - [H,我] G - [J, K]所以当我想要 E 和它的所有后代时,我使用键递归地获取它的孩子和他们的孩子,它允许我从任何节点开始向下移动。该解决方案提供了很好的速度提升,但是对于 15,000 个节点,在代码中重建我的树大约需要 5000 次缓存命中(更糟糕的情况......从 E 开始。性能基于起始节点的位置,导致超级用户看到性能最差)。这仍然很快,但似乎很健谈。我喜欢这样一个事实,即我可以随时通过从键列表中弹出一个节点来删除它,而无需重建我的整个缓存。在 UI 上可视化地构建树的速度也很快。
第二次尝试
我的另一个想法是从数据库中获取层次结构,构建树并将其存储在 RAM (redis) 中,然后将整个事物拉出内存(它的大小约为 2 MB,已序列化)。这给了我一个对 redis 的调用(不是很健谈)来拉出整个树,找到用户父节点,然后下降以获取所有子项。这些调用很频繁,在网络层向下传递 2 MB 似乎很大。这也意味着如果不拉下树并编辑并将其全部推回,我就无法轻松添加/删除和项目。此外,通过 HTTP 构建的按需树意味着每个请求必须拉下 2MB 才能获得直接子节点(使用第一个解决方案非常小)。
那么您认为哪种解决方案更好(从长期来看,它会继续增长)。两者都快得多,并且减轻了数据库的负担。或者他们是我没有想到的更好的方法来实现这一点?
谢谢
【问题讨论】:
-
你是怎么解决这个问题的?
标签: c# performance caching redis hierarchical-data