spModel多层关联查询问题和解决方法

#1 小满哥

     现在正在尝试二次开发一个微型BBS,不可避免的用到了表之间的关联查询。SP的关联查询做得好像还不错,很方便,但是效率方面我猜想应该还有可以优化的地方。
    我所说的多层关联是这样的。比如A表和B表关联,B表又和C表关联。这个时候如果你用spLinker的话,返回的结果只有B表的内容,而B表和C表的关联将被忽略。
    我碰到的具体情况就是我有一张主题表(A),关联了评论表(B),获取评论;评论表(B)又关联了用户表(C),获取评论用户名。当我用spLinker关联查询主题表的时候,只查询到了主题表(A)和评论表(B)的内容,而用户表(C)的评论用户名没有数据。
    从源代码来看,SpeedPHP\Core\spModel.php 大概第863行,函数private function do_select( $thelinker, $run_result ),函数最后一句。
return spClass($thelinker['fclass'])->$do_func($fcondition, $thelinker['sort'], $thelinker['field'], $thelinker['limit'] );
A表查询完毕以后,这里直接是返回了B表查询的数据,而对B表关联查询进行忽略了。
    可能从程序复杂性和可控性以及效率方面考虑,没有实现spLinker的多层关联查询(简单的想了一下,是有点复杂,而且使用起来不是很顺滑)。但是spModel还是提供了另一种方式来实现——自己编写函数实现多层关联查询。自己写函数实现分页查询和下一级表关联查询方法,自写函数调用自写函数,实现多层关联查询,优化性能,还可以实现函数级的缓存。但是,我很懒,我还没有实现。参见:[数据模型] 数据函数复合调用

PS:第755行,这个地方可以优化一下吧。A表查询10条数据的话,B表还要查询10次,一共11次数据库操作。
}elseif( 'findAll' == $func_name || 'run' == $func_name ){
                                                foreach( $run_result as $single_key => $single_result )
                                                        $run_result[$single_key][$thelinker['map']] = $this->do_select( $thelinker, $single_result );

2013-01-11 10:26:36

#2 jake

80/20原则,spModel只是满足日常开发八成的常规操作封装,其他平时少用的操作建议直接用SQL执行。

根据统计和测试,一般项目spLinker不会影响效率,多个语句分开查询的方式和一条SQLjoin的方式其实效率上是几乎一样的。

不过更复杂的,或者开发中很少遇到(或者几乎多个项目都没一次)的情况,像三表关联这种,就不做支持了。

另外,要注意,其实三表或以上的表直接SQL关联,效率是非常低下的,比不上分开查询。

本帖属于交流讨论的性质,转移到交流版

2013-01-11 11:57:12

#3 小满哥

     受教了,把28法则给忘了。
    以下是我的多层关联查询。
/**
/**
     * 获取指定文章评论数据
     * @param int $aid 文章ID
     * @param int $pageno 当前页码
     * @param int $pagesize 每页记录数
     * @return array
     */
    function getComments($aid,$pageno=1,$pagesize=10){
        
        $this->linker['lib_user']['enabled']=true;
        //关联分页查询评论数据
        $coms = $this->spLinker()->spPager($pageno,$pagesize)->findAll(array('articleid'=>$aid),'id desc');
        
//        echo $this->dumpSql();exit();
        
        return $coms;
    }
我在评论表对象增加了一个方法getComments,用来分页获取指定文章的指定页评论数据,这里关联查询评论用户。在文章表对象增加了一个方法 getArticle ,用来获取指定文章内容以及第一页评论数据。在getArticle 函数中调用getComments 函数,这样就间接的实现了多层此多表关联查询。
    有时间还是尝试一下把这一段优化一下。
}elseif( 'findAll' == $func_name || 'run' == $func_name ){
                                                foreach( $run_result as $single_key => $single_result )
                                                        $run_result[$single_key][$thelinker['map']] = $this->do_select( $thelinker, $single_result );
                                        }elseif( 'create' == $func_name ){
尝试将多条SQL语句执行合并成为一条执行,这样效果应该会好点。

2013-01-11 12:54:51

#4 jake

小满哥 发表于 2013-1-11 12:54
受教了,把28法则给忘了。
    以下是我的多层关联查询。我在评论表对象增加了一个方法getComments,用 ...
80/20原则,spModel只是满足日常开发八成的常规操作封装,其他平时少用的操作建议直接用SQL执行。

根据统计和测试,一般项目spLinker不会影响效率,多个语句分开查询的方式和一条SQLjoin的方式其实效率上是几乎一样的

不过更复杂的,或者开发中很少遇到(或者几乎多个项目都没一次)的情况,像三表关联这种,就不做支持了。

另外,要注意,其实三表或以上的表直接SQL关联,效率是非常低下的,比不上分开查询。

2013-01-11 13:30:05