慢查询 - 帮助优化

时间:2009-06-05 07:31:30

标签: sql mysql optimization

嘿伙计们。这是question

的后续内容

根据商家的要求获取正确的数据并进行一些调整后,我现在已经掌握了这个小型野兽。此查询应该返回新求职者注册的总数和新上传的简历的数量:

SELECT COUNT(j.jobseeker_id) as new_registrations,
(
    SELECT 
      COUNT(c.cv_id)
    FROM 
      tb_cv as c, tb_jobseeker, tb_industry
    WHERE
      UNIX_TIMESTAMP(c.created_at) >= '1241125200'
    AND 
      UNIX_TIMESTAMP(c.created_at) <= '1243717200'
    AND 
      tb_jobseeker.industry_id = tb_industry.industry_id
) 
AS uploaded_cvs
FROM 
  tb_jobseeker as j, tb_industry as i
WHERE
  j.created_at BETWEEN '2009-05-01' AND '2009-05-31'
AND
  i.industry_id = j.industry_id
GROUP BY i.description, MONTH(j.created_at) 

注意: - UNIX TIMESTAMP函数中的两个值作为参数从我们后端的报告模块传入。

每次我运行它时,MySQL都会悄悄地扼杀并插入到Interweb的以太网中。

非常感谢帮助。

更新:嘿伙计们。非常感谢所有深思熟虑和乐于助人的评论。我在这里只有2周的时间,所以我还在学习架构。所以,这个查询介于一个顽固的猜测之间。现在就开始回答你的所有问题了。

2 个答案:

答案 0 :(得分:6)

tb_cv未连接到子查询中的其他表。我想这是慢查询的根本原因。它会导致生成笛卡尔积,产生的行数比您可能需要的多得多。

除此之外,我会说您需要tb_jobseeker.created_attb_cv.created_attb_industry.industry_id上的索引,并且您可能希望摆脱子网中的UNIX_TIMESTAMP()次呼叫-query因为它们阻止使用索引。请改用BETWEEN和实际字段值。

这是我尝试理解您的查询并编写更好的版本。我想你想得到每个行业每月新求职者注册和新上传的简历:

SELECT 
  i.industry_id,
  i.description, 
  MONTH(j.created_at)            AS month_created,
  YEAR(j.created_at)             AS year_created,
  COUNT(DISTINCT j.jobseeker_id) AS new_registrations,
  COUNT(cv.cv_id)                AS uploaded_cvs
FROM 
  tb_cv AS cv
  INNER JOIN tb_jobseeker AS j ON j.jobseeker_id = cv.jobseeker_id
  INNER JOIN tb_industry  AS i ON i.industry_id  = j.industry_id
WHERE
  j.created_at BETWEEN '2009-05-01' AND '2009-05-31'
  AND cv.created_at BETWEEN '2009-05-01' AND '2009-05-31'
GROUP BY 
  i.industry_id,
  i.description, 
  MONTH(j.created_at),
  YEAR(j.created_at)

在编写查询时我注意到的一些事情:

  • 您最后没有输出的GROUP BY值。为什么? (我已将分组字段添加到输出列表。
  • 您在子查询中加入三个表,而只使用其中一个表中的值。为什么?除了过滤掉没有求职者或行业附属的简历记录之外,我不知道它会有什么好处 - 我很难想象。 (我删除了整个子查询,改为使用简单的COUNT
  • 您的子查询每次都返回相同的值。您是否可能意味着以某种方式将其与行业相关联?
  • 子查询针对分组查询中的每条记录运行一次,而不包含在聚合函数中。

答案 1 :(得分:0)

首先,可能值得将'UNIX_TIMESTAMP'转换移动到等式的另一侧(即,对&gt; =和&lt; =的另一侧的文字时间戳值执行反向函数) 。这将避免内部查询必须为每条记录执行转换,而不是为查询执行一次。

另外,为什么uploaded_cvs查询没有任何where子句将其链接到外部查询?我在这里错过了什么吗?