php/Mysql 最好的树形结构
Posted
技术标签:
【中文标题】php/Mysql 最好的树形结构【英文标题】:php / Mysql best tree structure 【发布时间】:2011-05-06 20:07:55 【问题描述】:我必须构建一棵树,其中包含大约 300 个节点。树没有深度限制。所以它可以有 3 或 15 个级别。每个节点可以有无限数量的子节点。
优先级是尽可能快地获得完整的树/子树,但我有时也需要添加节点或移动节点,但不那么频繁。
我想知道在数据库中存储树的最佳方式以及在 php 中检索数据的最佳方式。
【问题讨论】:
这是 mysql 推荐的:dev.mysql.com/tech-resources/articles/hierarchical-data.html @OMGPonies:该链接已损坏:( @hakre:该站点是 mysql 站点上的内容的复制/粘贴:mikehillyer.com/articles/managing-hierarchical-data-in-mysql 【参考方案1】:您可以使用嵌套集模型,因为它会产生非常高效的查询。查看Managing Hierarchical Data in MySQL 并阅读名为嵌套集模型的部分。
如果您使用像 Doctrine 这样的 ORM,请使用 includes nested set capabilities。
有些人可能很难掌握 left 和 right 的嵌套集合概念。 我发现使用这些数字来类比 open 的行号/close 标记在 XML 文档中,人们发现它更容易掌握。
以上面 MySQL 链接中的数据为例:
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
| 7 | MP3 PLAYERS | 11 | 14 |
| 8 | FLASH | 12 | 13 |
| 9 | CD PLAYERS | 15 | 16 |
| 10 | 2 WAY RADios | 17 | 18 |
+-------------+----------------------+-----+-----+
如果您将 lft、rgt 字段用作 XML 文档的行号,您会得到:
1. <electronics>
2. <televisions>
3. <tube>
4. </tube>
5. <lcd>
6. </lcd>
7. <plasma>
8. </plasma>
9. </televisions>
10. <portable electronics>
11. <mp3 players>
12. <flash>
13. </flash>
14. </mp3 players>
15. <cd players>
16. </cd players>
17. <2 way radios>
18. </2 way radios>
19. </portable electronics>
20. </electronics>
以这种方式查看它可以使某些人更容易可视化生成的嵌套集层次结构。它还更清楚地说明了为什么这种方法可以提高效率,因为它可以选择整个节点而无需多次查询或连接。
【讨论】:
除非你说得这么简单,否则我永远无法理解保存层次结构数据。 为行号类比投票。太棒了,我现在立刻“明白”了!【参考方案2】:这是一篇很棒的文章:Managing Hierarchical Data in MySQL。我用了很久。
如果你有一些数学能力,你就能真正理解它为什么这么厉害!
【讨论】:
【参考方案3】: <?php
$host = "localhost";
//Database user name.
$login = "root";
//Database Password.
$dbpass = "";
$dbname = "abc";
$PDO = new PDO("mysql:host=localhost;dbname=$dbname", "$login", "$dbpass");
$rows = array();
$sql = 'SELECT id, parent_id, name FROM employee';
$query = $PDO->prepare($sql);
$query->execute();
$rows = array();
if (!$query)
$error = 'Error fetching page structure, for nav menu generation.';
exit();
while($row = $query->fetch(PDO::FETCH_ASSOC))
if( strcasecmp($row['parent_id'],'null') === 0 || empty($row['parent_id']) )
$row['parent_id'] = null;
$rows[] = $row;
// covert raw result set to tree
$menu = convertAdjacencyListToTree(null,$rows,'id','parent_id','links');
// echo '<pre>',print_r($menu),'</pre>';
// display menu
echo themeMenu($menu,1);
/*
* ------------------------------------------------------------------------------------
* Utility functions
* ------------------------------------------------------------------------------------
*/
/*
* Convert adjacency list to hierarchical tree
*
* @param value of root level parent most likely null or 0
* @param array result
* @param str name of primary key column
* @param str name of parent_id column - most likely parent_id
* @param str name of index that children will reside ie. children, etc
* @return array tree
*/
function convertAdjacencyListToTree($intParentId,&$arrRows,$strIdField,$strParentsIdField,$strNameResolution)
$arrChildren = array();
for($i=0;$i<count($arrRows);$i++)
if($intParentId === $arrRows[$i][$strParentsIdField])
$arrChildren = array_merge($arrChildren,array_splice($arrRows,$i--,1));
$intChildren = count($arrChildren);
if($intChildren != 0)
for($i=0;$i<$intChildren;$i++)
$arrChildren[$i][$strNameResolution] = convertAdjacencyListToTree($arrChildren[$i][$strIdField],$arrRows,$strIdField,$strParentsIdField,$strNameResolution);
return $arrChildren;
/*
* Theme menu
*
* @param array menu
* @param runner (depth)
* @return str themed menu
*/
function themeMenu($menu,$runner)
$out = '';
if(empty($menu))
return $out;
$out.='<ul>';
foreach($menu as $link)
$out.= sprintf(
'<li class="depth-%u">%s%s</li>'
,$runner
,$link['name']
,themeMenu($link['links'],($runner+1))
);
$out.='</ul>';
return $out;
?>
【讨论】:
以上是关于php/Mysql 最好的树形结构的主要内容,如果未能解决你的问题,请参考以下文章