首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有更适合存储此类数据的解决方案?

问是否有更适合存储此类数据的解决方案?
EN

Stack Overflow用户
提问于 2014-03-05 16:22:28
回答 3查看 63关注 0票数 0

我需要做一些关于数据结构的研究,但我不确定要搜索哪个名称。

假设的场景是这样的:我有一家拥有数千名员工的企业。每个员工可以向他们上面的多个人报告(树向上分支),每个员工也可以监督他们下面的许多人(树也向下分支)。

下面是我目前使用的两个非常简单的表格:

代码语言:javascript
复制
employee (id, Firstname, Lastname)
employee_structure (id, ParentID, ChildID)

我使用一个递归的PHP函数来显示一个员工的树(向下的树方向)。但是在每个级别上运行SELECT查询来查找每个“节点”的下一个级别是非常耗时的。这就产生了超过30万个直接和间接的关系。随着结构随着时间的推移而增长,情况只会变得更糟。

我需要找出是否有更适合于存储和检索这样的结构的解决方案(在MySQL中,甚至是其他语言)。

如果有人能给我指出正确的方向,或者给出一些有用的提示,我将不胜感激。

EN

回答 3

Stack Overflow用户

发布于 2014-03-05 16:36:59

员工之间存在m:n关系。在MySql数据库中使用连接表是正确的。

要显示树,您不需要为每个节点运行SELECT。

查询输出应如下所示

代码语言:javascript
复制
+--------------------------------------+
| id | Firstname | Lastname | ChildIDs |
+--------------------------------------+

其中ChildIDs是相关ID的GROUP_CONCAT值。

查询:

代码语言:javascript
复制
SELECT 
e.id, e.Firstname, e.Lastname, GROUP_CONCAT(c.ChildID) 
FROM employee AS e
JOIN employee_structure AS c ON c.ParentID = e.id

如果数据太大,内存耗尽,请使用某种分页来使结果保持较小。

然后,您可以遍历此结果并显示完整的树,而无需运行另一个SELECT。

代码语言:javascript
复制
function printEmployees($id, $indent) {
    echo str_repeat(' ', $indent * 2) . $employees[$id]['Firstname'] . ' ' . $employees[$id]['Lastname'] . PHP_EOL;
    if (!empty($employees[$id]['ChildIDs'])) {
        foreach (explode(',', $employees[$id]['ChildIDs']) as $childID) {
            printEmployees($childID, $indent + 1);
        }
    }
}
票数 0
EN

Stack Overflow用户

发布于 2014-03-05 19:15:37

大多数分层模型都基于树的概念(嵌套集、邻接、线程二进制)-其中每个节点只有一个父节点。这在你的情况下显然不是真的。现在您有一个网络模型(考虑使用像OQGraph这样的图形数据库引擎?)。

按照它的立场,你有一个大数据完整性问题,确保图是非循环的(某人不是自己的老板)。这可能发生在简单的自连接树层次结构中,但由于数据模型更简单且更容易识别,这种情况发生的可能性要小得多。据我所知,避免这种情况的唯一方法是添加一个明确的属性,指示每个员工的级别-每个员工只能监督较低级别的员工。

现在先把它放在一边(尽管解决方案取决于级别的概念,至少相对于起始点是这样),如果是我,我会使用临时表和递归存储过程,类似于...

代码语言:javascript
复制
CREATE TEMPORARY TABLE oversees (
   employee_id INT NOT NULL,
   level INT NOT NULL,
   PRIMARY KEY employee_id
);

CREATE PROCEDURE populate_oversees(p_emp_id INT, p_max_levels INT)
(
   INSERT INTO oversees (employee_id, level) VALUES (p_emp_id, p_max_levels);
   call recurse_oversees(max_levels);
);
CREATE PROCEDURE recurse_oversees(p_level INT)
(
   INSERT INTO oversees o1 (employee_id, level)
   SELECT e.id, p_level-1
   FROM employee e
   INNER JOIN employee_structure es
   ON e.id=es.ChildId
   WHERE es.ParentId IN (
      SELECT o2.employee_id
      FROM oversees o2
      WHERE level=p_level
   );

   IF (p_level>1) THEN recurse_oversees(p_level-1);
);

SELECT *
FROM oversees
ORDER BY level DESC;
票数 0
EN

Stack Overflow用户

发布于 2014-03-05 16:40:24

请看一看Managing Hierarchical Data in MySQL文章,特别是The Nested Set Model部分。在这篇文章的末尾你也有很好的参考资料。

归根结底,就是在您的SQL表中使用left和right值(父id之外)来表示树节点。这种方法使您能够在单个查询中检索完整的树、节点路径、所有叶节点和更多内容。

这种方法的缺点是插入和删除节点有点复杂,因为您必须正确地维护left和right的值。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22192202

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档