表示分层任务/子任务的最佳方式(MySQL / PHP)

时间:2014-04-12 22:42:23

标签: php mysql laravel hierarchy nested-sets

我正在制作一个简单的待办事项应用程序(Laravel4 / MySQL),它需要能够创建任务和子任务(将其限制为最多3级)

我正在检查Laravel herehere的嵌套集实现。这是否符合我的要求?

我猜测嵌套集会全局保存层次结构数据(比如说,基于每个用户或每个项目),对于像项目数量有限的多级菜单这样的项目更好。 对于我的案例来说,最好的实现是什么,其中数百个用户拥有大量项目,每个项目都有数百个多级任务/子任务?如果我为我的情况实现嵌套集,是否会有不必要的遍历/开销?

2 个答案:

答案 0 :(得分:4)

我的回答是关闭表。

我在SQL Antipatterns(https://books.google.com/books/about/SQL_Antipatterns.html?id=Ghr4RAAACAAJ)一书中读到了几种解决层次结构的方法。我绝对推荐读这本书。

我最喜欢的实现层次结构的方法是通过闭包表。这是一个很好的来源,可以深入解释它们:http://technobytz.com/closure_table_store_hierarchical_data.html

总结:制作一个跟踪层次结构中实际项目的表(例如task_id,task_description,time_opened等)和另一个跟踪关系的表。第二个表应该包含task_id和parent_task_id之类的东西。这些表的最佳技巧是跟踪每个父子关系,而不仅仅是直接的父子关系。因此,如果您的任务1具有子任务,任务2和任务2具有子任务,任务3,则跟踪任务1和任务2之间以及任务1和任务3之间的父子关系。 / p>

关闭表与嵌套集的权衡是闭包表占用更多内存,但在执行操作时需要的计算量更少。这是因为您存储每个任务之间的每个关系(这需要内存),并且所有这些关系的简单可用性使得RDBMS更快地获取关系信息。

希望这有帮助!

答案 1 :(得分:4)

我建议您阅读 Managing hierarchical data in mysql 文章。

简而言之,

CREATE TABLE category(
        category_id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(20) NOT NULL,
        parent INT DEFAULT NULL
);

INSERT INTO category VALUES(1,'ELECTRONICS',NULL),(2,'TELEVISIONS',1),(3,'TUBE',2),
        (4,'LCD',2),(5,'PLASMA',2),(6,'PORTABLE ELECTRONICS',1),(7,'MP3 PLAYERS',1),(8,'FLASH',7),
        (9,'CD PLAYERS',6),(10,'2 WAY RADIOS',6);

SELECT * FROM category ORDER BY category_id;
+-------------+----------------------+--------+
| category_id | name                 | parent |
+-------------+----------------------+--------+
|           1 | ELECTRONICS          |   NULL |
|           2 | TELEVISIONS          |      1 |
|           3 | TUBE                 |      2 |
|           4 | LCD                  |      2 |
|           5 | PLASMA               |      2 |
|           6 | PORTABLE ELECTRONICS |      1 |
|           7 | MP3 PLAYERS          |      6 |
|           8 | FLASH                |      7 |
|           9 | CD PLAYERS           |      6 |
|          10 | 2 WAY RADIOS         |      6 |
+-------------+----------------------+--------+

查询检索所有数据:

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
WHERE t1.name = 'ELECTRONICS';

仅检索叶子名称:

SELECT t1.name FROM
category AS t1 LEFT JOIN category as t2
ON t1.category_id = t2.parent
WHERE t2.category_id IS NULL;

检索一条路径:

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
WHERE t1.name = 'ELECTRONICS' AND t3.name = 'FLASH';