使用子查询更快地获取 50k 行 - Laravel 5.6

Get 50k rows faster with subqueries - Laravel 5.6

下面的查询是从有 50k 行的 table 中获取候选人的详细信息。包括职位、地区和就业类型。候选人有就业类型、工作、地区的基本信息在另一个 table 有外键关系。

$candidates =  DB::table('candidates')
->join('role_users', function($join){
    $join->on('candidates.user_id', '=', 'role_users.user_id');
    $join->where('role_users.role_id', 6);    
})
->join('candidate_statuses', 'candidates.candidate_status_id', '=', 'candidate_statuses.id')
->join('employment_types', 'candidates.employment_types_id', '=', 'employment_types.id')
->select(
    'candidates.id', 
    'candidates.user_id', 
    'candidates.candidate_code', 
    'candidates.full_name as name', 
    'employment_types.title AS employment_type',
    DB::raw("(SELECT GROUP_CONCAT(candidate_jobs.job_id SEPARATOR ',') FROM candidate_jobs WHERE candidate_jobs.candidate_id = candidates.id) as job_ids"),
    DB::raw("(SELECT GROUP_CONCAT(regions.name SEPARATOR ',') FROM candidate_regions INNER JOIN regions ON regions.id=candidate_regions.region_id WHERE candidate_regions.candidate_id = candidates.id) as regions"),
    'role_users.email',
    'role_users.login_at',
    'candidates.is_deleted')
->where('candidates.candidate_status_id', '!=' , 6)
->where('candidates.is_deleted', $request->is_deleted)
->orderBy('candidates.first_name')
->groupBy('candidates.id')
->paginate(10);
}
select  `candidates`.`id`, `candidates`.`user_id`, `candidates`.`candidate_code`,
        `candidates`.`first_name`,
        `candidates`.`last_name`, `candidates`.`full_name` as `name`,
        `candidates`.`profile_img`, `candidates`.`candidate_status_id`,
        `candidates`.`employment_types_id`,
        `employment_types`.`title` as `employment_type`,
    (
        SELECT  GROUP_CONCAT(candidate_jobs.job_id SEPARATOR ',')
            FROM  candidate_jobs
            WHERE  candidate_jobs.candidate_id = candidates.id
    ) as job_ids,
    (
        SELECT  GROUP_CONCAT(regions.name SEPARATOR ',')
            FROM  candidate_regions
            INNER JOIN  regions  ON regions.id=candidate_regions.region_id
            WHERE  candidate_regions.candidate_id = candidates.id
    ) as regions,
        `candidates`.`formatted_mobile_number`, `candidates`.`place`,
        `candidates`.`post_code`, `role_users`.`email`, `role_users`.`login_at`,
        `role_users`.`email`, `candidates`.`has_access`, `candidates`.`is_deleted`
    from  `candidates`
    inner join  `role_users`  ON `candidates`.`user_id` = `role_users`.`user_id`
      and  `role_users`.`role_id` = ?
    inner join  `candidate_statuses`
        ON `candidates`.`candidate_status_id` = `candidate_statuses`.`id`
    inner join  `employment_types`
        ON `candidates`.`employment_types_id` = `employment_types`.`id`
    where  (`candidates`.`candidate_status_id` in (?))
      and  `candidates`.`candidate_status_id` != ?
      and  `candidates`.`is_deleted` = ?
    group by  `candidates`.`id`
    order by  `candidates`.`first_name` asc 

在我的本地机器上需要 2/ 3 秒才能得到结果,但在生产环境中需要很长时间。 有人可以帮忙吗?

第二部分好像没必要:

           `candidates`.`candidate_status_id` in (?))
      and  `candidates`.`candidate_status_id` != ?

进行这些匹配可避免对结果进行额外传递

    group by  `first_name`,    `id`
    order by  `first_name` asc, id

可能有用的索引:

candidates:  INDEX(candidate_status_id, is_deleted, first_name, id, user_id)
role_users:  INDEX(user_id,  email, login_at, role_id)
candidate_jobs:  INDEX(candidate_id,  job_id)
candidate_regions:  INDEX(candidate_id, region_id)