下面的查询需要超过 30 秒才能获取 10 条记录。
SELECT
`u`.*,`f`.`functional_area`,`f`.`is_active` AS `is_ft_active`,`pe`.`title`,`pe`.`company`,
(
SELECT
cv_file
FROM
profile_cvs
WHERE
profile_cvs.user_id = u.id AND profile_cvs.is_active = 1 AND deleted_at IS NULL
ORDER BY
profile_cvs.id
DESC
LIMIT 1
) AS cv_file
FROM
`users` AS `u`
LEFT JOIN `functional_areas` AS `f` ON `f`.`id` = `u`.`functional_area_id`
LEFT JOIN `profile_experiences` AS `pe` ON `pe`.`user_id` = `u`.`id`
LEFT JOIN `profile_cvs` AS `pc` ON `pc`.`user_id` = `u`.`id`
LEFT JOIN `profile_summaries` AS `ps` ON `ps`.`user_id` = `u`.`id`
LEFT JOIN `profile_educations` AS `ped` ON `ped`.`user_id` = `u`.`id`
LEFT JOIN `profile_skills` AS `psk` ON `psk`.`user_id` = `u`.`id`
LEFT JOIN `job_skills` AS `js` ON `js`.`id` = `psk`.`job_skill_id`
LEFT JOIN `admins` AS `ad` ON `ad`.`id` = `u`.`created_by`
WHERE
(`js`.`job_skill` IN("HVAC")) OR(`f`.`functional_area` LIKE "%HVAC %") OR(`u`.`search` LIKE "%HVAC%") OR(`ps`.`summary` LIKE "% HVAC%") OR(`ped`.`degree_title` LIKE "HVAC")
GROUP BY
`u`.`id`
ORDER BY CASE WHEN
js.job_skill LIKE '%HVAC %' THEN 1 ELSE 0
END + CASE WHEN f.functional_area LIKE '%HVAC %' THEN 1 ELSE 0
END + CASE WHEN ps.summary LIKE '% HVAC%' THEN 1 ELSE 0
END + CASE WHEN u.search LIKE '% HVAC %' THEN 1 ELSE 0
END
DESC
,
`u`.`is_blocked` ASC,
`js`.`job_skill` DESC,
`f`.`functional_area` DESC,
`u`.`search` DESC,
`u`.`id` DESC
LIMIT 10;
我们检查了此查询中使用的每一列都已建立索引。用户表的记录也少于 1,00,000 条。 所以请解释一下为什么这个查询花费了太多时间。
我发现您的查询中存在一些可能会减慢速度的问题。
SELECT 子句中的子查询:
cv_file
的子查询会显着减慢查询速度,因为它是针对结果集中的每一行执行的。考虑将此逻辑移至联接或在单独的查询中获取它。
JOIN:您有多个 LEFT JOIN,可能仅对某些查询有用。评估您是否需要所有这些联接来获取仅 10 条记录。减少连接数量可以提高性能。
WHERE 子句:WHERE 子句在多个表之间使用 OR 条件,这可能会导致全表扫描。尝试通过合并这些条件或使用全文搜索(如果数据库支持)来更有效地重构这些条件。
范围限制:如果可能,请在查询中尽早应用过滤器,以限制后续阶段处理的行数。
GROUP BY Optimization:
GROUP BY
子句可能会导致数据库对大型数据集进行排序和分组。如果目的是删除重复项,请考虑是否有更有效的方法来实现此目的,例如在较小的结果集上使用 DISTINCT。
这是解决其中一些要点的概念重写:
WITH UserSubset AS (
SELECT u.id
FROM users AS u
WHERE u.search LIKE "%HVAC%"
ORDER BY u.is_blocked ASC, u.id DESC
LIMIT 10
)
SELECT
u.*, f.functional_area, f.is_active AS is_ft_active, pe.title, pe.company,
pc.cv_file
FROM
UserSubset us
JOIN
users u ON us.id = u.id
LEFT JOIN
functional_areas f ON f.id = u.functional_area_id
LEFT JOIN
profile_experiences pe ON pe.user_id = u.id
LEFT JOIN
(SELECT user_id, MAX(id) AS latest_cv_id FROM profile_cvs WHERE is_active = 1 AND deleted_at IS NULL GROUP BY user_id) AS latest_cv ON latest_cv.user_id = u.id
LEFT JOIN
profile_cvs pc ON pc.id = latest_cv.latest_cv_id
-- Add other necessary joins here, ensuring they relate to UserSubset to limit the scope