有没有更适合存储此类数据的解决方案?

时间:2014-03-05 08:22:28

标签: php mysql

我需要对数据结构进行一些研究,但我不确定要搜索的名称。

以下是假设情景: 我与数千名员工开展业务。 每个员工都可以向他们上面的多个人报告(树枝向上伸出),每个员工也可以监督他们下面的许多人(树也向下伸出)。

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

employee (id, Firstname, Lastname)
employee_structure (id, ParentID, ChildID)

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

我需要找出是否有更适合存储和检索此类结构的解决方案(在MySQL中,甚至是其他东西)。

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

3 个答案:

答案 0 :(得分:0)

员工之间存在m:n关系。 在你的MySql数据库中使用connctiontable是对的。

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

您的查询输出应该类似于

+--------------------------------------+
| id | Firstname | Lastname | ChildIDs |
+--------------------------------------+

其中ChildIDs是相关ID的GROUP_CONCAT值。

查询:

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。

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);
        }
    }
}

答案 1 :(得分:0)

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

就目前而言,你有一个很大的数据完整性问题,确保图表是非循环的(有人不是他们自己的老板)。这可以通过简单的自连接树层次结构发生,但由于数据模型更简单,更不容易识别。我知道避免这种情况的唯一方法是添加一个显示每个员工级别的显式属性 - 每个员工只能监督较低级别的员工。

暂时抛开这一点(虽然解决方案取决于关卡的概念,至少相对于起点)如果是我,我会选择临时表和递归存储过程,例如。 ...

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;

答案 2 :(得分:-1)

请查看Managing Hierarchical Data in MySQL文章,尤其是The Nested Set Model部分。您还可以在本文末尾找到很好的参考资料。

归结为在SQL表中使用leftright值(在父ID旁边)来表示树节点。这种方法使您能够在单个查询中检索完整树,节点路径,所有叶节点等。

这种方法的缺点是在某种意义上插入和删除节点要复杂一些,你必须正确地保持leftright值。