tp5 php MySQL的in查询效率太低的解决办法之一(buildSql构造子查询)

TP5.1例子一(一个条件):

    		//1、购买单个试卷,不是组合套餐中的试卷
				$rso=Db::name('order')
				->field('o.id,op.limit,op.pid,o.pay_time,o.time,o.number')
				->alias('o')
				->join('order_product op','o.number = op.number')
				->where('o.deleted',0)//0正常 1回收站
				->where('o.state',1)// 0未支付 1已支付 2已经关闭
				->where('o.user_id',$uid)
				->where('op.user_id',$uid)
				->where('op.controller','Testpaper')
				->buildSql();
			
			//$rs = Db::table([$rso => ' od'])
			$rs = Db::table($rso .' od')
			->leftJoin('test_paper t','od.pid = t.id')
			->order('od.pay_time', 'desc')
			->select();
			 
			//echo Db::table($rso . 'od')->getLastSql();

tp5 php MySQL的in查询效率太低的解决办法之一(buildSql构造子查询)_第1张图片

重点:只能是Db::table,不能用Db::name

 

例子二(多个条件):thinkphp5 对union之后的查询进行分页

    			//1、购买试卷_单独(不是组合)  不分用户是否过期
                    $t_sql_num1 = Db::field('op.pid')
					    ->name('order')
					    ->alias('o')
					    ->leftjoin('order_product op','o.number = op.number')
						->where('o.deleted',0)
						->where('o.state',1)
						->where('op.controller','Testpaper')
						->where('o.user_id',$uid)
					    ->buildSql();
					    
    			//2、购买组合中的试卷  不分用户是否过期
                    $t_sql_num2 = Db::field('opc.pid')
					    ->name('order_product_clist')
					    ->alias('opc')
					    ->leftjoin('order_product op','opc.opid = op.id')
					    ->leftjoin('order op','o.number = op.number')
						->where('o.deleted',0)
						->where('o.state',1)
						->where('op.controller','Combination')
						->where('opc.type_mold',3)//类型 1直播 2点播 3题库 4商城 5其它 6简历模板 7会员充值
						->where('o.user_id',$uid)
						->union([$t_sql_num1])
					    ->buildSql();
					    
//				//3、合并条件
						    
					Db::table($t_sql_num2 . ' t')
					    ->leftjoin('test_paper_question pq','t.pid = pq.paper_id')
					    ->order('id', 'desc')
					    ->select();

 

        $m_acc = model('...');
        $a = $m_acc->field('... as a,...')->where(...)->group('...')->buildSql();
        $b = $m_acc->field('... as a,...')->where(...)->group('...')->buildSql();
        $c = $m_acc->field('... as a,...')->where(...)->group('...')->buildSql();
        $e = $m_acc->field('... as a,...')->where(...)->group('...')->buildSql();
        $e = $m_acc->field('... as a,...')->where(...)->group('...')->union([$a,$b,$c,$d])->buildSql();
        //到这里,已经可以把$e当做一个正常表来进行操作了,什么分页、group by、where随便用,使用"DB::table($e . ' a')"即可
        $res = Db::table($e.' a')
            ->field('...')
            ->group('...')
            ->paginate(5);
        return json($res);

上面我是根据一个表里字段的不同分出了几个表然后union在一起的,当然也可以使用不同的表来操作,但需要注意的是一定要保证union的几个表必须具有相同的字段,这个使用filed方法保证一致性即可

转载:https://blog.jkloozx.com/?id=163

 

例子三:thinkphp5 union的使用

tp5 php MySQL的in查询效率太低的解决办法之一(buildSql构造子查询)_第2张图片

/**
     * 根据订单号统计播放次数
     * @param  string $orderId    订单号(子订单号)
     * @param  string $page
     * @return mixed|false|array
     */
    public function getCount($orderId=''){
        if(empty($orderId)){
            return false;
        }
        $picArr=Db::name('pic')->where('order_id',$orderId)->column('id,pic_id');
        if(empty($picArr)){
            return false;
        }
        $picIds=[];
        foreach ($picArr as $pa){
            $picIds[]=$pa['id'];
        }
        if(empty($picIds)){
            return false;
        }
        $nowMonthDate=date('Ymd');
        $nowMonth=date('Ym');
        $selectTable='detail_'.$nowMonth;
        $sqlArr=[];
        //昨天之前的数据
        $allDetail=Db::name('detail')->where(['pic_id'=>['in',$picIds]])->field("sum(play_time) as timesum,date")->group('date')->buildSql();
        $sqlArr[]=$allDetail;
        //今天的数据
        $cpmMonthDetail=Db::name($selectTable)->where(['pic_id'=>['in',$picIds],'create_date'=>$nowMonthDate])->field("count(id) as timesum,create_date as date")->group('create_date')->buildSql();
        $sqlArr[]=$cpmMonthDetail;
        //tp5有个问题,用了union之后用where和分页有有问题,所有通过构建子查询来达到目标。子查询里面本身要写完整的查询(指把所有需要查询的都union起来),再通过一个中间表(detail_temp)来组建查询ORM。
        $temp=Db::name('cpm_detail_temp')->field("count(id) as timesum,create_date as date")->union($sqlArr)->buildSql();
        $finall = Db::table($temp." a")
            ->where(['timesum'=>['neq',0],'date'=>['neq',0]]) //把中间表数据过滤掉
            ->order('date desc')
            ->paginate(
                10,false,[
                    'type'     => 'Bootstrap',
                    'var_page' => 'page',
                    'child_order_id'=>$orderId,
                    'path'=>"javascript:AjaxPage($orderId,[PAGE]);",
                ]
            );
        $arrData=$finall->toArray();
        $arrData=$arrData['data'];
        if(!empty($arrData)){
            foreach ($arrData as &$val){
                $val['date']=date('Y-m-d',strtotime($val['date']));
            }
        }
        return empty($finall)?false:['page'=>$finall->render(),'data'=>$arrData];
    }
!

转载:https://blog.csdn.net/lixinyuan1213/article/details/80302086

 

最近在做一个MySQL数据库的查询(查询出指定时间之后凡是上传过图片的用户所在的镇和镇的管理员名),查询语句如下:

 SELECT DISTINCT user_name,town_name FROM t_farmers WHERE id IN 
(SELECT DISTINCT farmer_id FROM t_farmers_images WHERE create_time>='2017-07-05') 
其中farmers表有六千多记录,farmers_images表有近20万条记录,查询效率极低,此查询估计能够耗十分钟的时间,无法忍受,于是寻找解决办法,

网上有说加索引解决的,但是个人感觉这个数据量并不大,加索引即使能够解决问题,等日后数据量逐渐增大之时这似乎并不是一个非常好的办法。

网上还有说把in改为exist,但是查询效率似乎并没有什么改变。通过搜阅资料得知in适合用于子表小的情况,而exist适合子表大主表小的情况,(仅代表一家之言,可能有不到之处,日后细究)。

解决方法如下:

经对数据库方面的文章参考,最终找到了一个方法,把in改为左连接右连接的方式,于是把sql语句改为如下:

 SELECT DISTINCT b.user_name,b.town_name FROM (SELECT DISTINCT farmer_id FROM t_farmers_images WHERE create_time>='2017-08-18') a LEFT JOIN t_farmers b ON a.farmer_id=b.id 

LEFT JOIN:只查左边的表,就是说只查六千多记录就行
查询效率瞬间提升,几乎感觉不到有什么延迟。
详细的左连接,右连接,内连接等的查询和哪种适合左边表大,哪种适合右边表大,哪种查询具体适合什么情形,请自行网上查询。

查询2月1号之后,总数之和超过300的用户:

SELECT mm.*,c.user_name,c.town_name,c.name,c.tel,c.card_id,c.onecard_id FROM (
SELECT a.farmer_id,SUM(death_number) FROM t_farmers_details a
WHERE a.date_time>='2017-02-01' GROUP BY a.farmer_id HAVING SUM(death_number)>=300 ) mm
LEFT JOIN t_farmers c ON c.id=mm.farmer_id

此外做项目时有经常需要用到多表查询的情况,这种情况下一般不适用笛卡尔积,因为笛卡尔积的开销太大,查询太慢,到现在才明白为什么两年前别人的项目中都用左连接,右连接之类的查询,而没有使用笛卡尔积了,两年了才明白别人当初的业务逻辑,还需要加把劲更加努力进步!
--------------------- 
作者:pengyufight 
来源:CSDN 
原文:https://blog.csdn.net/pengyufight/article/details/77523404 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

tp5 子语句方法:

首先构造子查询SQL,可以使用下面三种的方式来构建子查询。

使用fetchSql方法

fetchSql方法表示不进行查询而只是返回构建的SQL语句,并且不仅仅支持select,而是支持所有的CURD查询。

$subQuery = Db::table('think_user')
    ->field('id,name')
    ->where('id', '>', 10)
    ->fetchSql(true)
    ->select();

生成的subQuery结果为:

SELECT `id`,`name` FROM `think_user` WHERE `id` > 10 

使用buildSql构造子查询

$subQuery = Db::table('think_user')
    ->field('id,name')
    ->where('id', '>', 10)
    ->buildSql();

生成的subQuery结果为:

( SELECT `id`,`name` FROM `think_user` WHERE `id` > 10 )

调用buildSql方法后不会进行实际的查询操作,而只是生成该次查询的SQL语句(为了避免混淆,会在SQL两边加上括号),然后我们直接在后续的查询中直接调用。

然后使用子查询构造新的查询:

Db::table($subQuery . ' a')
    ->where('a.name', 'like', 'thinkphp')
    ->order('id', 'desc')
    ->select();

生成的SQL语句为:

SELECT * FROM ( SELECT `id`,`name` FROM `think_user` WHERE `id` > 10 ) a WHERE a.name LIKE 'thinkphp' ORDER BY `id` desc

使用闭包构造子查询

IN/NOT INEXISTS/NOT EXISTS之类的查询可以直接使用闭包作为子查询,例如:

Db::table('think_user')
    ->where('id', 'IN', function ($query) {
        $query->table('think_profile')->where('status', 1)->field('id');
    })
    ->select();

生成的SQL语句是

SELECT * FROM `think_user` WHERE `id` IN ( SELECT `id` FROM `think_profile` WHERE `status` = 1 )
Db::table('think_user')
    ->whereExists(function ($query) {
        $query->table('think_profile')->where('status', 1);
    })->find();

生成的SQL语句为

SELECT * FROM `think_user` WHERE EXISTS ( SELECT * FROM `think_profile` WHERE `status` = 1 ) 

除了上述查询条件外,比较运算也支持使用闭包子查询

 

https://www.kancloud.cn/manual/thinkphp5_1/354032

 

 

 

你可能感兴趣的:(php,MY,SQL,thinkphp5)