公司的产品的主体类型架构是一个树结构,其实说白了就是以一个父级ID来组织而已。
其中有个需求是要把所有主体类型树拿出来,这个简单呀,其实就是一个递归查询就解决了。
表结构如图:
我马上在类里面写了下面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']);
}
直接贴效果:
哈哈,多次测试,速度基本都是提高了几十倍,第二种方法只用了几十毫秒,连缓存都不需要啦~~
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 [];
}
速度将大大提升!