我在Yii中有一个代表树的模型,带有以下MySQL表:
CREATE TABLE IF NOT EXISTS `nodes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`node` varchar(255) NOT NULL,
[ something more not necessary to display here ]
`parentid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
) ENGINE=InnoDB;
此模型我有以下关系:
return array(
'parentnode'=>array(self::BELONGS_TO, 'Nodes', 'parentid'),
'childnode'=>array(self::HAS_MANY, 'Nodes', 'parentid'),
);
我正在使用CTreeView来显示树。使用$ model-> childnode以递归方式迭代所有节点并使用parentid = 0构建源数组。这是迭代函数:
public static function nodetree($params) { //finds all top-level nodes
$retval=array();
$nodes=Nodes::model()->findAllByAttributes(array('parentid'=>0));
foreach($nodes as $anode)
$retval[]=Nodes::nodearray($anode, $params);
}
这是递归函数。
public static function nodearray($_node, $params) { // finds children
$retval=array(
'text'=>$_node->node, //may differ based on options
'id'=>$_node->id,
'expanded'=>false, //may differ based on options
'children'=>array(),
);
foreach ($_node->childnode as $c_node)
$retval['children'][]=Nodes::nodearray($c_node, $params);
return $retval;
}
由于Yii的开销,这可能不是最快的方法。在没有运行其他应用程序的开发服务器上,页面生成时间超过1秒。节点超过1K,并在需要时由用户更新。
如何更快地生成树/页?
答案 0 :(得分:2)
嗯,我回答自己的问题很遗憾,但不知怎的,我找到了一个解决方案。
我创建了一个缓存表:
CREATE TABLE IF NOT EXISTS `treecache` (
`param` varchar(255) NOT NULL,
`cachedtree` mediumtext NOT NULL,
PRIMARY KEY (`param`)
) ENGINE=InnoDB;
我更改了nodetree函数,如下所示:
public static function nodetree($param) { //finds all top-level nodes
$paramstr = serialize($param);
if (strlen($paramstr)<256) {
$oval=Yii::app()->db->createCommand('SELECT cachedtree FROM treecache WHERE param=:param')->queryRow(true, array('param'=>$paramstr));
if (isset($oval['cachedtree'])) return unserialize($oval['cachedtree']);
}
$retval=array();
$nodes=Nodes::model()->findAllByAttributes(array('parentid'=>0));
foreach($nodes as $anode)
$retval[]=Nodes::nodearray($anode, $param);
if (strlen($paramstr)<256)
Yii::app()->db->createCommand('INSERT INTO treecache VALUES (:param, :cachedtree)')->execute(array('param'=>$paramstr, 'cachedtree'=>serialize($retval)));
return $retval;
}
此外,为了应对节点更改,我在模型中添加了一个新功能:
public function afterSave() {
Yii::app()->db->createCommand('TRUNCATE treecache')->execute();
return parent::afterSave();
}
这不会加速树生成过程,但会根据参数缓存生成的树,并且比迭代/递归更快地返回结果。我仍然对任何评论持开放态度......
答案 1 :(得分:2)
这是我迄今为止测试过的最有效的方法。源自http://blog.ideashower.com/post/15147134343/create-a-parent-child-array-structure-in-one-pass
public static function nodetree($param=array()) {
$refs = array();
$list = array();
$nodes = Yii::app()->db->createCommand('select * from nodes')->queryAll();
foreach ($nodes as $data) {
$thisref = &$refs[ $data['id'] ];
$thisref['parentid'] = $data['parentid'];
$thisref['text'] = $data['node'];
if ($data['parentid'] == 0) {
$list[ $data['id'] ] = &$thisref;
} else {
$refs[ $data['parentid'] ]['children'][ $data['id'] ] = &$thisref;
}
}
return $list;
}