我正在使用树行为来存储有序的项目列表。
当我向树中添加新元素时,我将其重新排序,调用“reorder()”函数。这很慢。我一直在尝试很多东西。我的最后一次测试是一个包含70个元素的单个表(1个父项和69个孩子)。用于reorder()函数的时间是1分钟& 20秒我正在使用MySQL,我在id,parent_id,rght和lft字段中都有索引。
我可能做错了什么?
谢谢
答案 0 :(得分:0)
我也花了一些时间调查这个。
事实证明,重新排序功能非常低效。基本上它将第一个项目的左侧和右侧字段设置为高值,然后重新排序其余字段。然后它对第二个项目执行相同的操作等。对于只有一百个项目的树,最终会运行数万个查询。
我使用以下代码对其进行了整理。这样做只会更新每个记录一次,并保留左右值之间的差距。它递归地遍历项目并正确地重新排序。
在app / Model / Behavior中创建一个名为“BRTreeBehavior.php”的新文件,然后修改模型的$ actsAs字段以使用BRTree而不是Tree。
<?php
/**
* Copyright 2015, Perthweb Pty Ltd
*
*/
App::uses('TreeBehavior', 'Model/Behavior');
/**
* BetterReorderTree Behavior.
*
* Improves reorder of tree behavior
*
*/
class BRTreeBehavior extends TreeBehavior {
/**
* Reorder method.
*
* Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters.
* This method does not change the parent of any node.
*
* Requires a valid tree, by default it verifies the tree before beginning.
*
* Options:
*
* - 'id' id of record to use as top node for reordering
* - 'field' Which field to use in reordering defaults to displayField
* - 'order' Direction to order either DESC or ASC (defaults to ASC)
* - 'verify' Whether or not to verify the tree before reorder. defaults to true.
*
* @param Model $Model Model instance
* @param array $options array of options to use in reordering.
* @return boolean true on success, false on failure
* @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::reorder
*/
public function reorder(Model $Model, $options = array()) {
$options = array_merge(array('id' => null, 'field' => $Model->displayField, 'order' => 'ASC', 'verify' => true, 'startIndex' => null), $options);
extract($options);
if ($verify && !$this->verify($Model)) {
return false;
}
$verify = false;
extract($this->settings[$Model->alias]);
$fields = array($Model->primaryKey, $field, $left, $right);
$sort = $field . ' ' . $order;
$nodes = $this->children($Model, $id, true, $fields, $sort, null, null, $recursive);
$cacheQueries = $Model->cacheQueries;
$Model->cacheQueries = false;
if ($nodes) {
if($id == null){
$index = 1;
}
else if($startIndex == null){
$index = $nodes[0][$Model->alias][$left];
}
else {
$index = $startIndex;
}
foreach ($nodes as $node) {
$id = $node[$Model->alias][$Model->primaryKey];
$difference = $node[$Model->alias][$right] - $node[$Model->alias][$left];
$nodeData = array(
$Model->alias => array(
$Model->primaryKey => $id,
$left => $index,
$right => $index + $difference
)
);
$Model->create();
$Model->save($nodeData, array('validate' => false, 'callbacks' => false, 'fieldList' => array($left, $right)));
$Model->clear();
$startIndex = $index + 1;
if ($difference != 1) {
$this->reorder($Model, compact('id', 'field', 'order', 'verify', 'startIndex'));
}
$index += $difference + 1;
}
}
$Model->cacheQueries = $cacheQueries;
return true;
}
}