在我的MYSQL数据库中,我有2个表:
+-------------------+ +---------------------------------+
| tags | | relationships |
+----+--------------+ +---------+---------+------+------+
| id | tag | | x_table | y_table | x_id | y_id |
+----+--------------+ +---------+---------+------+------+
| 1 | parent 1 | | tags | tags | 1 | 2 |
| 2 | child 1 | | tags | tags | 1 | 3 |
| 3 | child 2 | | tags | tags | 3 | 4 |
| 4 | grandchild 1 | +---------+---------+------+------+
+----+--------------+
我需要将这些关系加载到一个多维数组中。孩子的数量可以改变,深度可以改变。每个关系树的深度也不同。
现在我已经读过递归函数比PHP之类的解释语言的循环慢,并且想知道是否甚至可以用循环编写它,如果是这样的话,它是否会更快,资源密集程度更低使用递归函数?
多维数组的结构应如下:
array(
'id' => $id_from_db,
'tag' => $tag_from_db,
'children' => array( /* Just like parent array or false/NULL */ )
)
编辑: SQLfiddle here
编辑:我创建了递归函数来实现这个目标:
private function get_tags($id = false){
global $pdo;
$tags = array();
if(!$id)
$info = $pdo->query("SELECT DISTINCT
t.id,
t.tag
FROM tags t
JOIN relationships r
ON r.x_table = 'tags'
AND r.y_table = 'tags'
AND t.id NOT IN ( SELECT rb.y_id FROM relationships rb WHERE x_table = 'tags' AND y_table = 'tags' )
ORDER BY t.tag");
else
$info = $pdo->query("SELECT DISTINCT
t.id,
t.tag
FROM tags t
JOIN relationships r
ON r.x_table = 'tags'
AND r.y_table = 'tags'
AND r.x_id = " .(int)$id."
AND r.y_id = t.id
ORDER BY t.tag");
while($tag = $info->fetch(PDO::FETCH_ASSOC))
$tags[] = array('tag' => $tag['tag'], 'children' => $this->get_tags($tag['id']) );
if(!count($tags))
return false;
return $tags;
}
答案 0 :(得分:3)
你可以使用引用,如果你不介意在1 go(2个查询)中取出所有内容(可能标记的总量应该低于几百,并且你可以缓存生成的构造一段时间):< / p>
//fill tags
$tags[] = array()
foreach($pdo->query('SELECT * FROM tags')->fetchAll(PDO::FETCH_ASSOC) as $tag){
$tags[$tag['id']] = $tag;
}
//add relationships
$relation_query = $pdo->query("SELECT * FROM relationships
WHERE x_table='tags' AND y_table = 'tags'");
foreach($relation_query->fetchAll(PDO::FETCH_ASSOC) as $relationship){
//ensure targets exists:
if(!isset($tags[$relationship['x_id '])) $tags[$relationship['x_id '] = array();
if(!isset($tags[$relationship['y_id '])) $tags[$relationship['y_id '] = array();
if(!isset($tags[$relationship['x_id ']['children']))
$tags[$relationship['x_id ']['children'] = array();
//add as reference
$tags[$relationship['x_id ']['children'] = &$tags[$relationship['y_id '];
}
//pick the tag you want:
var_dump($tags[1]);
var_dump($tags[4]);
不是closure
table ,或只是path enumeration(向前滑动18,但整个事情值得一读)会给你更大的性能,并且可以只查询一个子树。 Bill Karwin的大道具。
答案 1 :(得分:0)
感谢little help from Wrikken,我能够提出代码:
public function get_tags(){
global $pdo;
$tags = $childs = array();
foreach($pdo->query('SELECT * FROM tags')->fetchAll(PDO::FETCH_ASSOC) as $tag)
$tags[$tag['id']] = $tag;
foreach($pdo->query("SELECT * FROM relationships WHERE x_table='tags' AND y_table='tags'")->fetchAll(PDO::FETCH_ASSOC) as $relationship){
if(!isset($tags[$relationship['x_id']]['children']))
$tags[$relationship['x_id']]['children'] = array();
$tags[$relationship['x_id']]['children'][] = &$tags[$relationship['y_id']];
$childs[] = $relationship['y_id'];
}
while($childs)
unset($tags[array_pop($childs)]);
return $tags;
}
这会返回我请求的数组,但是如果没有子元素,那么children元素就不存在了(实际上比将它设置为false更好)。
<强>基准:强>
我使用每个函数运行了一个简单的time php file.php > /dev/null
,结果显示使用循环总共0.751s
,而递归总计1.303s
。这虽然循环了一小组数据。根据代码的结构,我假设随着数据集的增加,递归会呈指数级增长,而循环的执行时间会以线性方式增加。
总而言之,我认为循环比递归明显更快。