MySql 查询花费太多时间,而所有列都已索引

问题描述 投票:0回答:1

下面的查询需要超过 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 条。 所以请解释一下为什么这个查询花费了太多时间。

mysql optimization query-optimization
1个回答
0
投票

我发现您的查询中存在一些可能会减慢速度的问题。

  1. SELECT 子句中的子查询

    cv_file
    的子查询会显着减慢查询速度,因为它是针对结果集中的每一行执行的。考虑将此逻辑移至联接或在单独的查询中获取它。

  2. JOIN:您有多个 LEFT JOIN,可能仅对某些查询有用。评估您是否需要所有这些联接来获取仅 10 条记录。减少连接数量可以提高性能。

  3. WHERE 子句:WHERE 子句在多个表之间使用 OR 条件,这可能会导致全表扫描。尝试通过合并这些条件或使用全文搜索(如果数据库支持)来更有效地重构这些条件。

  4. 范围限制:如果可能,请在查询中尽早应用过滤器,以限制后续阶段处理的行数。

  5. 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
© www.soinside.com 2019 - 2024. All rights reserved.