美文网首页
以代码处理代替循环查询数据库

以代码处理代替循环查询数据库

作者: 10xjzheng | 来源:发表于2017-03-25 14:04 被阅读177次

公司的产品的主体类型架构是一个树结构,其实说白了就是以一个父级ID来组织而已。

其中有个需求是要把所有主体类型树拿出来,这个简单呀,其实就是一个递归查询就解决了。

表结构如图:

Paste_Image.png

我马上在类里面写了下面5行代码:

public static function getAll1($pid)
{
        $children = self::find()->select('id, pid, name')->where(['pid' => $pid])->asArray()->all();
        foreach ($children as $key => $value) {
            $children[$key]['children'] = self::getAll1($value['id']);
        }
        return $children;
 }

所有树就都拉出来啦。

但是发现当数据库有10几棵树,400条数据的时候,每次查询要耗费2s左右的时间,刚开始为了快我就直接加个redis缓存。对于有强迫症的我不能忍,于是今天有空了就想做一下优化。

优化的方向是用php处理来代替在递归里面循环查询。

于是我又写了下面一种方法:

/**
* 只查一次,再对数据处理
**/
 public static function getAll2()
    {
        $organization = self::find()->select('id, pid, name')->asArray()->all();
        return self::getChildrenByRecursion(0, $organization);
    }
/**
* 根据父ID查询子集
*/
  public static function getChildren($organizations, $pid)
    {
        $res = [];
        foreach ($organizations as $key => $value) {
            if($value['pid'] == $pid) {
                $res[] = $value;
            }
        }
        return $res;
    }
/**
* 递归获取全部
*/
   public static function getChildrenByRecursion($pid, $organization)
   {
        $children = self::getChildren($organization, $pid);
        foreach ($children as $key => $value) {
            $children[$key]['children'] = self::getChildrenByRecursion($value['id'], $organization);
        }
        return $children;
   }

然后就写了个测试

    /**
     * 测试
     */
    public function actionTest()
    {
        $start1 = microtime(true);
        $all1 = EntityType::getAll1(0);
        print_r(['first way used time' => microtime(true)-$start1]);
        $start2 = microtime(true);
        $all2 = EntityType::getAll2();
        print_r(['second way used time' => microtime(true)-$start2]);
        print_r(['res1 equal res2 ?' => $all1 == $all2 ? 'yes' : 'no']);
    }

直接贴效果:

Paste_Image.png Paste_Image.png

哈哈,多次测试,速度基本都是提高了几十倍,第二种方法只用了几十毫秒,连缓存都不需要啦~~

2017-08-09更新
getChildren方法的算法复杂度可以降为O(1),无需遍历。$organizations参数可以先处理:

 /**
     * 处理获取到的全部机构,将pid作为$key
     * @param $organizations
     */
    public static function dealOrganizations($organizations)
    {
        $newOrganizations = [];
        foreach ($organizations as $organization) {
            $newOrganizations[$organization['pid']][] = $organization;
        }
        return $newOrganizations;
    }

取子集可以修改为:

 /**
     * 获取该父ID下的机构
     * @param array $organization 公众号下的所有机构
     * @param int $pid 父ID
     * @return array
     */
    public static function getChildren($organization, $pid)
    {
        if(!empty($organization[$pid])) {
            ArrayHelper::multisort($organization[$pid], 'sort');
            return $organization[$pid];
        }
        return [];
    }

速度将大大提升!

相关文章

网友评论

      本文标题:以代码处理代替循环查询数据库

      本文链接:https://www.haomeiwen.com/subject/otrcottx.html