过滤查询大约需要 50 秒才能加载
Filtering query takes around 50 seconds to load
我有一个页面,用户可以在其中使用非常广泛的过滤器集搜索职位空缺。其中两个过滤器是复选框,用户可以在其中 select 兴趣和可访问性。当 if selected 时,至少其中一个必须出现在某个空位上才能作为结果显示。
我正在使用 CodeIgniter PHP 框架。
使我的网站崩溃的生成查询示例如下所示:
SELECT v.*
, o.name as orgname
, GROUP_CONCAT(DISTINCT(vi.interest_id)) interests
, GROUP_CONCAT(DISTINCT(i.description)) interestnames
, GROUP_CONCAT(DISTINCT(i.name_brown)) interesticons
, GROUP_CONCAT(DISTINCT(e.engagement_key)) engagement_key
FROM vacancies v
LEFT
JOIN organization o
ON v.org_id = o.org_id
LEFT
JOIN vacancy_interests vi
ON v.vacancy_id = vi.vacancy_id
LEFT
JOIN interests i
ON vi.interest_id = i.interest_id
LEFT
JOIN engagement e
ON v.engagement = e.engagement_id
LEFT
JOIN cities_be c
ON v.address_city_id = c.cities_be_id
LEFT
JOIN vacancy_accessibility va
ON v.vacancy_id = va.vacancy_id
WHERE v.is_deleted != 1
AND v.status = 1
GROUP
BY v.vacancy_id
HAVING MAX(vi.interest_id IN (3,4,6,7,9,10)) > 0
AND MAX(va.accessibility_id IN (2,1,3,4,5,6)) > 0
ORDER
BY v.modified_time DESC
LIMIT 18
我在我的网站上使用的每个过滤器都很顺利并给我结果,但是 vacancy_accessibility table 使我的搜索页面在使用时完全崩溃。在我有大约 100 个职位空缺的本地主机上,它运行良好且快速。但是我的生产服务器,我有大约 11,000 个空缺,一切都变得糟糕,搜索需要大约 5-6 分钟才能完成。
我已经执行了上面粘贴的 MySQL workbench 中的查询,查询计算大约需要 52 秒。
如果我执行相同的查询,但只使用 selected 兴趣(这意味着我不通过 LEFT JOIN 加载可访问性 table,它工作得非常快(大约 0.1 秒).
这实际上并没有反过来工作,我已经尝试删除 interest left join 并且查询速度更快,但它仍然是大约 16 秒。请注意,我确实需要加入兴趣,所以这不是一个真正的选择,只是为了调试。
空缺可及性table实际上与vacancy_interests完全相同。它包含 vacancy_id 列和 accessibility_id 的参考列。空缺兴趣 table 包含 28k 行,而空缺可及性 table 仅包含 5.8k 行...
我确实注意到在可访问性 table 中没有设置 FK,而在兴趣 table 中设置了它们。我不确定这是否会导致如此大的延迟(实际上并没有那么多行)。
有人看到我的查询有什么问题导致我的页面崩溃吗?
您当前的Select存在几个问题:
- 它必须先进行所有连接,然后在开始过滤之前进行聚合
- 这些连接增加了行数,因为有些是 m-n 而不是 n-1,最终导致 GROUP_CONCAT(DISTINCT)
- 所有这些连接都是外部连接,从不减少行数
尝试尽快应用过滤器和 GROUP_CONCATs 并尽可能切换到内部联接。将这些规则应用于查询的第一部分:
SELECT `v`.*,
vi.interests,
vi.interestnames,
vi.interesticons
FROM `vacancies` AS `v`
JOIN
( -- Derived Table to apply filter & concat as soon as possible
-- also results in a single row per vacancy_id (n.1-join)
SELECT `vacancy_id`
,GROUP_CONCAT(i.interest_id) AS interests
,group_concat(i.description) AS interestnames -- DISTINCT probably not needed
,group_concat(i.name_brown) AS interesticons -- DISTINCT probably not needed
FROM `vacancy_interests` AS `vi`
JOIN
( SELECT interest_id
FROM `interests`
GROUP BY interest_id
HAVING Max(interest_id) IN (3, 4, 6, 7, 9, 10)
) AS `i`
ON `vi`.`interest_id` = `i`.`interest_id`
) AS `vi`
ON `v`.`vacancy_id` = `vi`.`vacancy_id`
...
现在使用连接将 accessibility_id 添加到类似的 Derived Table。当您应用所有过滤条件时,将整个 Select 放入另一个 Derived Table 中,包括 LIMIT (减少行数),最后连接剩余的表(如果可能再次使用内部连接)
我有一个页面,用户可以在其中使用非常广泛的过滤器集搜索职位空缺。其中两个过滤器是复选框,用户可以在其中 select 兴趣和可访问性。当 if selected 时,至少其中一个必须出现在某个空位上才能作为结果显示。
我正在使用 CodeIgniter PHP 框架。 使我的网站崩溃的生成查询示例如下所示:
SELECT v.*
, o.name as orgname
, GROUP_CONCAT(DISTINCT(vi.interest_id)) interests
, GROUP_CONCAT(DISTINCT(i.description)) interestnames
, GROUP_CONCAT(DISTINCT(i.name_brown)) interesticons
, GROUP_CONCAT(DISTINCT(e.engagement_key)) engagement_key
FROM vacancies v
LEFT
JOIN organization o
ON v.org_id = o.org_id
LEFT
JOIN vacancy_interests vi
ON v.vacancy_id = vi.vacancy_id
LEFT
JOIN interests i
ON vi.interest_id = i.interest_id
LEFT
JOIN engagement e
ON v.engagement = e.engagement_id
LEFT
JOIN cities_be c
ON v.address_city_id = c.cities_be_id
LEFT
JOIN vacancy_accessibility va
ON v.vacancy_id = va.vacancy_id
WHERE v.is_deleted != 1
AND v.status = 1
GROUP
BY v.vacancy_id
HAVING MAX(vi.interest_id IN (3,4,6,7,9,10)) > 0
AND MAX(va.accessibility_id IN (2,1,3,4,5,6)) > 0
ORDER
BY v.modified_time DESC
LIMIT 18
我在我的网站上使用的每个过滤器都很顺利并给我结果,但是 vacancy_accessibility table 使我的搜索页面在使用时完全崩溃。在我有大约 100 个职位空缺的本地主机上,它运行良好且快速。但是我的生产服务器,我有大约 11,000 个空缺,一切都变得糟糕,搜索需要大约 5-6 分钟才能完成。
我已经执行了上面粘贴的 MySQL workbench 中的查询,查询计算大约需要 52 秒。
如果我执行相同的查询,但只使用 selected 兴趣(这意味着我不通过 LEFT JOIN 加载可访问性 table,它工作得非常快(大约 0.1 秒). 这实际上并没有反过来工作,我已经尝试删除 interest left join 并且查询速度更快,但它仍然是大约 16 秒。请注意,我确实需要加入兴趣,所以这不是一个真正的选择,只是为了调试。
空缺可及性table实际上与vacancy_interests完全相同。它包含 vacancy_id 列和 accessibility_id 的参考列。空缺兴趣 table 包含 28k 行,而空缺可及性 table 仅包含 5.8k 行... 我确实注意到在可访问性 table 中没有设置 FK,而在兴趣 table 中设置了它们。我不确定这是否会导致如此大的延迟(实际上并没有那么多行)。
有人看到我的查询有什么问题导致我的页面崩溃吗?
您当前的Select存在几个问题:
- 它必须先进行所有连接,然后在开始过滤之前进行聚合
- 这些连接增加了行数,因为有些是 m-n 而不是 n-1,最终导致 GROUP_CONCAT(DISTINCT)
- 所有这些连接都是外部连接,从不减少行数
尝试尽快应用过滤器和 GROUP_CONCATs 并尽可能切换到内部联接。将这些规则应用于查询的第一部分:
SELECT `v`.*,
vi.interests,
vi.interestnames,
vi.interesticons
FROM `vacancies` AS `v`
JOIN
( -- Derived Table to apply filter & concat as soon as possible
-- also results in a single row per vacancy_id (n.1-join)
SELECT `vacancy_id`
,GROUP_CONCAT(i.interest_id) AS interests
,group_concat(i.description) AS interestnames -- DISTINCT probably not needed
,group_concat(i.name_brown) AS interesticons -- DISTINCT probably not needed
FROM `vacancy_interests` AS `vi`
JOIN
( SELECT interest_id
FROM `interests`
GROUP BY interest_id
HAVING Max(interest_id) IN (3, 4, 6, 7, 9, 10)
) AS `i`
ON `vi`.`interest_id` = `i`.`interest_id`
) AS `vi`
ON `v`.`vacancy_id` = `vi`.`vacancy_id`
...
现在使用连接将 accessibility_id 添加到类似的 Derived Table。当您应用所有过滤条件时,将整个 Select 放入另一个 Derived Table 中,包括 LIMIT (减少行数),最后连接剩余的表(如果可能再次使用内部连接)