减少查询量并提高类别和子类别查询的性能

时间:2015-07-07 14:39:32

标签: php mysql

编辑3:通过将flatten方法更改为仅合并数组(如果不为空),将其降低到300-500 ms。

编辑2:通过仅为非空数组调用array_replace将其降低到1.6秒。现在剩下要做的就是优化函数sort_categories_and_sub_categories。那就是现在的瓶颈。如果我删除,我会降到300毫秒。有什么想法吗?

get_all_categories_and_sub_categories

foreach(array_keys($categories) as $id)
{

    $subcategories = $this->get_all_categories_and_sub_categories($id, $depth + 1);

    if (!empty($subcategories))
    {
        $categories = array_replace($categories, $subcategories);
    }
}

修改

通过在get_all方法中执行缓存,我将性能提高了50%以上(6秒 - > 2.5秒)。它将查询量从3000减少到1.我仍然想知道为什么它很慢。

我有以下方法来获取类别和嵌套子类别。如果用户有几百(或千)个顶级类别,则会为每个类别执行一系列查询以查找子级。在一个案例中,我有3000个类别,它做了3000个查询。有没有办法优化这个以减少查询?或者,我应该检查他们是否有很多类别,不要尝试显示嵌套。

function get_all_categories_and_sub_categories($parent_id = NULL, $depth = 0)
{
    $categories = $this->get_all($parent_id);
    if (!empty($categories))
    {
        foreach($categories as $id => $value)
        {
            $categories[$id]['depth'] = $depth;
        }

        foreach(array_keys($categories) as $id)
        {
            $categories = array_replace($categories, $this->get_all_categories_and_sub_categories($id, $depth + 1));
        }

        return $categories;
    }
    else
    {           
        return $categories;
    }
}


function get_all($parent_id = NULL, $limit=10000, $offset=0,$col='name',$order='asc')
{
    static $cache = array();

    if (!$cache)
    {
        $this->db->from('categories');
        $this->db->where('deleted',0);
        if (!$this->config->item('speed_up_search_queries'))
        {
            $this->db->order_by($col, $order);
        }

        $this->db->limit($limit);
        $this->db->offset($offset);

        foreach($this->db->get()->result_array() as $result)
        {
            $cache[$result['parent_id'] ? $result['parent_id'] : 0][] = array('name' => $result['name'], 'parent_id' => $result['parent_id'], 'id' => $result['id']);
        }
    }

    $return = array();

    $key = $parent_id == NULL ? 0 : $parent_id;
    if (isset($cache[$key]))
    {   
        foreach($cache[$key] as $row)
        {
            $return[$row['id']] = array('name' => $row['name'], 'parent_id' => $row['parent_id']);
        }
        return $return;
    }

    return $return;

}


function sort_categories_and_sub_categories($categories)
{
    $objects = array();
    // turn to array of objects to make sure our elements are passed by reference
    foreach ($categories as $k => $v) 
    {
        $node = new StdClass();
        $node->id = $k;
        $node->parent_id = $v['parent_id'];
        $node->name = $v['name'];
        $node->depth = $v['depth'];
        $node->children = array();
        $objects[$k] = $node;
    }


    // list dependencies parent -> children
    foreach ($objects as $node)
    {
        $parent_id = $node->parent_id;
        if ($parent_id !== null)
        {
            $objects[$parent_id]->children[] = $node;
        }
    }

    // clean the object list to make kind of a tree (we keep only root elements)
    $sorted = array_filter($objects, array('Category','_filter_to_root'));

    // flatten recursively
    $categories = self::_flatten($sorted);

    $return = array();

    foreach($categories as $category)
    {
        $return[$category->id] = array('depth' => $category->depth, 'name' => $category->name, 'parent_id' => $category->parent_id);
    }

    return $return;
}   

static function _filter_to_root($node)
{
    return $node->depth === 0;
}

static function _flatten($elements) 
{
    $result = array();

    foreach ($elements as $element) 
     {
        if (property_exists($element, 'children')) 
          {
            $children = $element->children;
            unset($element->children);
        } 
          else 
          {
            $children = null;
        }

        $result[] = $element;

        if (isset($children)) 
          {
                $flatened = self::_flatten($children);

                if (!empty($flatened))
                {                 
                    $result = array_merge($result, $flatened);
                } 
          }
    }
    return $result;
}

0 个答案:

没有答案