2

我正在使用 Tree Behavior 来存储有序的项目列表。

当我向树中添加新元素时,我重新排序它调用“reorder()”函数。它非常慢。我一直在尝试很多事情。我的最后一个测试是一个包含 70 个元素(1 个父元素和 69 个子元素)的表。reorder() 函数所用的时间是 1 分 20 秒。我正在使用 MySQL,并且在 id、parent_id、rght 和 lft 字段中有索引。

我可能做错了什么?

谢谢

4

1 回答 1

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;
    }


}
于 2015-04-17T03:51:31.030 回答