使用子查询更快地获取 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)
下面的查询是从有 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)