代码之家  ›  专栏  ›  技术社区  ›  Midiane

慢速查询-优化帮助

  •  1
  • Midiane  · 技术社区  · 16 年前

    嘿,伙计们。这是这个的后续行动 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时间戳函数中的两个值作为参数从后端的报告模块传入。

    每次我运行它,MySQL都会窒息,静静地徘徊在Interweb的以太中。

    感谢您的帮助。

    更新:嘿,伙计们。非常感谢您提供的所有周到和有益的意见。我在这里只工作了两周,所以我还在学习这个模式。所以,这个问题介于一个愚蠢的猜测和一个有根据的猜测之间。现在就开始回答你所有的问题。

    2 回复  |  直到 16 年前
        1
  •  6
  •   Tomalak    16 年前

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

    除此之外,我想说你需要索引 tb_jobseeker.created_at , tb_cv.created_at tb_industry.industry_id 你可能想摆脱 UNIX_TIMESTAMP() 子查询中的调用,因为它们阻止使用索引。使用 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)
    

    在编写查询时,我注意到了以下几点:

    • 您可以按最终不输出的值进行分组。为什么?( 我已经将分组字段添加到输出列表中。 )
    • 在子查询中联接三个表,而只使用其中一个表中的值。为什么?除了过滤掉那些没有求职者或行业背景的简历之外,我不知道这对我有什么好处——我很难想象。( 我删除了整个子查询并使用了 COUNT 相反。 )
    • 子查询每次返回相同的值。你是不是想用某种方式把它与这个行业联系起来?.
    • 对于分组查询中的每个记录,子查询只运行一次,而不包含在聚合函数中。
        2
  •  0
  •   jerryjvl    16 年前

    首先,最重要的是,将“unix时间戳”转换移到公式的另一侧(即,对>=和<=另一侧的文字时间戳值执行反向函数)可能是值得的。这将避免内部查询必须对每个记录执行转换,而不是对查询执行一次转换。

    还有,为什么 uploaded_cvs 查询没有任何WHERE子句将其链接到外部查询?我是不是错过了什么?