laravel eager loading to minimize queries

妖精的绣舞 提交于 2019-12-25 05:12:15

问题


I am using laravel with DDD Pattern and here is my code to make some analytics report for website...

My code from Repository...

//Abstract Entity
  public function getFirstBy($key, $value, array $with = array())
  {
    return $this->repository->getFirstBy($key, $value, $with);
  }


//Link Entity
$link = parent::getFirstBy('hash', $data['hash'], ['visits']);


//prepare report
          $report = [];

          //get dates difference
          $date1 = new \DateTime($data['from']);
          $date2 = new \DateTime($data['to']);
          $date_diff = $date2->diff($date1)->format("%a");

          $time_visits = $link->visits()->whereRaw('DATE(created_at) BETWEEN ? AND ?', array($date1, $date2))->groupBy('created_at')->orderBy('created_at', 'ASC')->get();

          //Total Visits
          $report['total_visits'] = $time_visits->count();

    //country visits
          $country_visits = $link->visits()->whereRaw('DATE(created_at) BETWEEN ? AND ?', array($date1, $date2))->orderBy('country_iso', 'ASC')->groupBy('country_iso')->get();

    //referrers
          $referer_visits = $link->visits()->whereRaw('DATE(created_at) BETWEEN ? AND ?', array($date1, $date2))->where('source', '!=', '')->orderBy('source', 'ASC')->groupBy('source')->get();

    //browsers
          $browser_visits = $link->visits()->whereRaw('DATE(created_at) BETWEEN ? AND ?', array($date1, $date2))->where('browser', '!=', '')->orderBy('browser', 'ASC')->groupBy('browser')->get();

    //os
          $os_visits = $link->visits()->whereRaw('DATE(created_at) BETWEEN ? AND ?', array($date1, $date2))->where('os', '!=', '')->orderBy('os', 'ASC')->groupBy('os')->get();


The code is working perfectly fine but executing 6 mysql queries which could be a big problem for larger usage... 

**sql queries dump...**

    select * from `link_visits` where `link_visits`.`link_id` = '4' and DATE(created_at) BETWEEN '2014-09-15 00:00:00' AND '2014-09-17 00:00:00' group by `created_at` order by `created_at` asc

    select * from `link_visits` where `link_visits`.`link_id` = '4' and DATE(created_at) BETWEEN '2014-09-15 00:00:00' AND '2014-09-17 00:00:00' group by `country_iso` order by `country_iso` asc

    select count(*) as total_visits, medium from `link_visits` where `link_visits`.`link_id` = '4' and DATE(created_at) BETWEEN '2014-09-15 00:00:00' AND '2014-09-17 00:00:00' group by `medium` order by `medium` asc

    select * from `link_visits` where `link_visits`.`link_id` = '4' and DATE(created_at) BETWEEN '2014-09-15 00:00:00' AND '2014-09-17 00:00:00' and `source` != '' group by `source` order by `source` asc

    select * from `link_visits` where `link_visits`.`link_id` = '4' and DATE(created_at) BETWEEN '2014-09-15 00:00:00' AND '2014-09-17 00:00:00' and `browser` != '' group by `browser` order by `browser` asc

    select * from `link_visits` where `link_visits`.`link_id` = '4' and DATE(created_at) BETWEEN '2014-09-15 00:00:00' AND '2014-09-17 00:00:00' and `os` != '' group by `os` order by `os` asc

Please suggest some good ways to optimize it better. thanks, i really need advanced help with this.

回答1:


you can use sub query in the relations for ex.

assuming $link is you model object

$link->with(['Visits'=>function($q){
       $q->whereRaw('DATE(created_at) BETWEEN ? AND ?', array($date1,$date2))->where('browser', '!=', '')->orderBy('browser', 'ASC')->groupBy('browser');
}])->get();

the inner query will filter all your records accordingly and the inner query will apply only in the Visits model

my suggestion is first fetch all the records without any filteration and then filter them in the object of collection with filter() method! so it will use only 1 query for visit to fetch all records then you only rearrange them using filter() method



来源:https://stackoverflow.com/questions/25879347/laravel-eager-loading-to-minimize-queries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!