|  RSS订阅  |  加入收藏

以关联表中的count计数作为主表的排序依据(进阶版)

上一篇关于以count计数作为排序依据的文章中最后讲到一个关于性能缺陷的分析。本文通过避开循环中使用count查询来完成相同的功能达到程序调优的目的。
摘要
...

上一篇文章在最后提到“在foreach循环中嵌套查询,这是非常耗费资源的”。当时考虑到本站应用场景简单,查询仅为百位数量级,性能损失忽略不计,就图简单没有深入去重写程序。今天得空,改造了下程序,通过操作数组来达到避开在遍历中使用count查询的目的。



先来通过thinkPHP的debug函数来测试下昨天的程序性能。

public function tagslst($num)
    {
        debug('begin');
        $tagRes=Db::name('tags')->select();
        foreach ($tagRes as $key => $value) {
            $tagsnum=Db::name('art_tag')->where('tags_id',$value['id'])->count();
            $tagsRes[$key]=array('sort'=>$tagsnum,'id'=>$value['id'],'tag_name'=>$value['tag_name']);//构造键名为sort,键值为count计数的新数组
        }
        foreach ($tagsRes as $k => $v) {
            $sort[]=$v['sort'];
        }
        array_multisort($sort, SORT_DESC, $tagsRes);//按tags数多少重新排序数组
        $tagsRes=array_slice($tagsRes,0,$num);//返回指定部分数据
        debug('end');
        dump(debug('begin','end').'s');
        dump(debug('begin','end','m').'kb');die;
        return $tagsRes;
    }

测试结果:运行耗时0.05s,内存占用112k。如图:

未标题-1.jpg

尝试颠倒查询顺序,通过内置数组函数进行计数。

上一篇是正常思维,通过查询tag表中的id在关联表中做count查询查询,最后以count依据截取需要的部分内容返回给控制器。缺陷在上一篇中提到,将第一步结果遍历后,代入count计数,有多少条数据就要查询多少次数据库,这个性能损失非常大。

今天换个思路来实现相同的目的。首先通过查询中间表中的tags_id列,将查询结果通过array_count_values函数做一个计数操作(关键就在这里,通过使用数组来计数达到避开循环中使用count查询。后续对这个数组截取需要的部分在tag表中使用in查询,返回最终查询结果即可。代码如下:

public function tagslst($num)
    {
        debug('begin');
        $tagidRes=Db::name('art_tag')->field('tags_id')->select();
        foreach ($tagidRes as $key => $value) {
            $tagids[]=$value['tags_id'];
        }
        $tagids=array_count_values($tagids);
        arsort($tagids);

        $tagids=array_slice($tagids,0,$num,true);
        
        foreach ($tagids as $k => $v) {
            $tag_idRes[]=$k;
        }

        $map['id']=['in',$tag_idRes];
        $tagRes=Db::name('tags')->where($map)->select();
        foreach ($tagRes as $key => $value) {
            foreach ($tag_idRes as $k => $v) {
                if($value['id']==$v){
                   $tagsRes[$k]=$value; 
                }
            }
        }
        ksort($tagsRes);
        debug('end');
        dump(debug('begin','end').'s');
        dump(debug('begin','end','m').'kb');die;
        return $tagsRes;
    }

同样,也使用debug函数测试下相应的性能数据。得到结果如下:

未标题-2.jpg

和前面的数据进行对比可见,耗时节约70%内存消耗减少50%以上。性能提升还是非常明显的。性能提升的关键在用PHP数组内置函数去代替了count计数查询,第二是截取需要的部分进行最后的数据查询。

打赏
  PHP    ThinkPHP    排序    
转载请注明出处,未经许可禁止商用!
西枫里 熊掌号
代码改变世界 ———— 半路出家,全程修道
发表评论
*依据《网络安全法》规定,您需实名认证后才能评论!
@沈唁志:我萌新,哈哈哈,只会CURD操作~
debug大佬~
@银色月航:不单单是聚合,任何查询在循环中都非常消耗资源和性能
确实,嵌套循环少用聚合查询