2013-09-26 29 views
1

我正在使用树行为来存储有序的项目列表。CakePHP中的树重排缓慢

当我添加新的元素到树中时,我重新命令它调用“reorder()”函数。它非常缓慢。我一直在尝试很多东西。我的最后一项测试是一张有70个元素的单桌(1个家长和69个孩子)。重新排序()函数所用的时间为1分钟20秒。我正在使用MySQL,并且在id,parent_id,rght和lft字段中都有索引。

我会做什么错?

谢谢

回答

0

我花了一些时间来研究这一个。

事实证明,重新排序功能是非常低效的。基本上,它将第一个项目的左侧和右侧字段设置为较高值,然后重新排序其余字段。然后它对第二个项目也是这样做的,等等,结果是成千上万的查询正在运行,对于只有一百个项目的树。

我用下面的代码对它进行了整理。它所做的只是更新每条记录一次,并且它保留了左值和右值之间的差距。它递归地遍历这些项目并对它们进行适当的重新排序。

在名为“BRTreeBehavior.php”的app/Model/Behavior中创建一个新文件,然后修改模型的$ 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; 
    } 


}