我正在使用树行为来存储有序的项目列表。
当我向树中添加新元素时,我会调用“reorder()”函数对其进行重新排序。它非常慢。我一直在尝试很多事情。我的最后一个测试是一个包含 70 个元素(1 个父元素和 69 个子元素)的表。 reorder() 函数使用的时间为 1 分 20 秒。我正在使用 MySQL,并且在 id、parent_id、rght 和 lft 字段中有索引。
我可能做错了什么?
谢谢
我也花了一些时间调查这个。
事实证明,重排序功能效率很低。 基本上,它将第一个项目的左侧和右侧字段设置为高值,然后对其余字段重新排序。 然后它对第二个项目执行相同的操作,依此类推。对于只有一百个项目的树,您最终会运行数万个查询。
我用下面的代码整理了它。 这样做的作用只是更新每条记录一次,并且保留左右值之间的间隙。 它递归地遍历项目并正确地重新排序。
在 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;
}
}