我可以将带有JOIN的SQL语句分解为较小的查询或优化查询吗?

时间:2017-12-08 02:06:35

标签: mysql sql query-optimization

我有查询破坏了我网站的某个区域。尝试加载以下SQL语句时,该站点永远旋转!我是sql语句的新手,这个特定的语句是由另一个开发人员创建的。有没有办法优化以下声明?或者将其分解为较小的语句,以便更快地运行?我很茫然!我感谢任何帮助。

SELECT
    `wp_quiz_users`.`Id`,
    `wp_quiz_users`.`SessionId`,
    `wp_quiz_users`.`Score`,
    `wp_quiz_users`.`Date`,
    `wp_quiz_users`.`Referrer`,
    `wp_quiz_users`.`ContactData`,
    (SELECT
        SUM(`wp_quiz_users_answers`.`AnswerValue`) 
    FROM
        `wp_quiz_users_answers` 
    JOIN
        `wp_quiz_questions` 
            ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id` 
    WHERE
        `wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id` 
        AND `wp_quiz_questions`.`Category` = 1) AS `SectionOne`,
    (SELECT
        SUM(`wp_quiz_users_answers`.`AnswerValue`) 
    FROM
        `wp_quiz_users_answers` 
    JOIN
        `wp_quiz_questions` 
            ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id` 
    WHERE
        `wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id` 
        AND `wp_quiz_questions`.`Category` = 2) AS `SectionTwo`,
    (SELECT
        SUM(`wp_quiz_users_answers`.`AnswerValue`) 
    FROM
        `wp_quiz_users_answers` 
    JOIN
        `wp_quiz_questions` 
            ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id` 
    WHERE
        `wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id` 
        AND `wp_quiz_questions`.`Category` = 3) AS `SectionThree`,
    (SELECT
        SUM(`wp_quiz_users_answers`.`AnswerValue`) 
    FROM
        `wp_quiz_users_answers` 
    JOIN
        `wp_quiz_questions` 
            ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id` 
    WHERE
        `wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id` 
        AND `wp_quiz_questions`.`Category` = 4) AS `SectionFour`,
    (SELECT
        SUM(`wp_quiz_users_answers`.`AnswerValue`) 
    FROM
        `wp_quiz_users_answers` 
    JOIN
        `wp_quiz_questions` 
            ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id` 
    WHERE
        `wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id` 
        AND `wp_quiz_questions`.`Category` = 5) AS `SectionFive` 
FROM
    `wp_quiz_users`

4 个答案:

答案 0 :(得分:5)

这个答案与Gordon相似,只不过它在单独的子查询中执行总和的聚合。这使得外部查询不需要聚合,因此从wp_quiz_users表中选择任何我们想要的列应该没有任何问题。

SELECT
    t1.Id,
    t1.SessionId,
    t1.Score,
    t1.Date,
    t1.Referrer,
    t1.ContactData,
    COALESCE(t2.SectionOne, 0)   AS SectionOne,
    COALESCE(t2.SectionTwo, 0)   AS SectionTwo,
    COALESCE(t2.SectionThree, 0) AS SectionThree,
    COALESCE(t2.SectionFour, 0)  AS SectionFour,
    COALESCE(t2.SectionFive 0)   AS SectionFive
FROM wp_quiz_users t1
LEFT JOIN
(
    SELECT
        t1.UserId,
        SUM(CASE WHEN t2.Category = 1 THEN t1.AnswerValue ELSE 0 END) AS SectionOne,
        SUM(CASE WHEN t2.Category = 2 THEN t1.AnswerValue ELSE 0 END) AS SectionTwo,
        SUM(CASE WHEN t2.Category = 3 THEN t1.AnswerValue ELSE 0 END) AS SectionThree,
        SUM(CASE WHEN t2.Category = 4 THEN t1.AnswerValue ELSE 0 END) AS SectionFour,
        SUM(CASE WHEN t2.Category = 5 THEN t1.AnswerValue ELSE 0 END) AS SectionFive
    FROM wp_quiz_users_answers t1
    INNER JOIN wp_quiz_questions t2
        ON t1.QuestionId = t2.id 
    GROUP BY t1.UserId
) t2
    ON t1.Id = t2.UserId;

答案 1 :(得分:1)

我认为你只想要条件聚合:

SELECT qu.*,
       SUM(CASE WHEN qq.Category = 1 THEN qa.AnswerValue END) as SectionOne, 
       SUM(CASE WHEN qq.Category = 2 THEN qa.AnswerValue END) as SectionTwo, 
       SUM(CASE WHEN qq.Category = 3 THEN qa.AnswerValue END) as SectionThree, 
       SUM(CASE WHEN qq.Category = 4 THEN qa.AnswerValue END) as SectionFour, 
       SUM(CASE WHEN qq.Category = 5 THEN qa.AnswerValue END) as SectionFive
FROM wp_quiz_users qu LEFT JOIN
     wp_quiz_users_answers qa
     ON qa.UserId = q.id  LEFT JOIN
     wp_quiz_questions qq
     ON qa.QuestionId = qq.id 
GROUP BY qu.UserId;

答案 2 :(得分:1)

这与Gordon Linoff的类似,但我想在某些时候添加一个关于语法的注释。 SQL的标准行为是所有不涉及聚合函数的列[例如sum()]应列在group by子句中。

SELECT
      wp_quiz_users.Id
    , wp_quiz_users.SessionId
    , wp_quiz_users.Score
    , wp_quiz_users.Date
    , wp_quiz_users.Referrer
    , wp_quiz_users.ContactData
    , SUM(CASE WHEN qq.Category = 1 THEN qa.AnswerValue END) AS sectionone
    , SUM(CASE WHEN qq.Category = 2 THEN qa.AnswerValue END) AS sectiontwo
    , SUM(CASE WHEN qq.Category = 3 THEN qa.AnswerValue END) AS sectionthree
    , SUM(CASE WHEN qq.Category = 4 THEN qa.AnswerValue END) AS sectionfour
    , SUM(CASE WHEN qq.Category = 5 THEN qa.AnswerValue END) AS sectionfive
FROM wp_quiz_users qu
LEFT JOIN wp_quiz_users_answers qa ON qa.UserId = q.id
LEFT JOIN wp_quiz_questions qq ON qa.QuestionId = qq.id
GROUP BY
      wp_quiz_users.Id
    , wp_quiz_users.SessionId
    , wp_quiz_users.Score
    , wp_quiz_users.Date
    , wp_quiz_users.Referrer
    , wp_quiz_users.ContactData
;

即。最好列出select子句中所需的所有列,以及group by子句中列出的所有“非聚合”列。

如果你看到使用这样的查询:

select * from sometable group by name

然后该查询依赖于可以打开或关闭的非标准MySQL扩展。如果关闭该扩展名,则依赖于扩展名的查询将开始失败。因此,谨慎的编码人员可以通过简单地列出group by子句中的所有非聚合列来避免这个潜在的问题。见:https://dev.mysql.com/doc/refman/5.7/en/group-by-modifiers.html

关于原始查询,它在select子句中包含许多“相关子查询”,并且正如您所发现的那样,性能很差。请注意这些

 select name
   , (select sum(value) from tablex 
      where tablex.id = table1.id   -- the "correlation" of tablex to table1 is here
     )
 from table1

然而,偶尔它们可能是一个不错的选择,所以尽管我们大多数时候都要避免使用它们,但我们不能说完全不使用它们。

答案 3 :(得分:0)

我会从

开始
    FROM (
        SELECT  ua.`UserId`,
                q.Category,
                SUM(ua.`AnswerValue`)
            FROM  `wp_quiz_users_answers` AS ua
            JOIN  `wp_quiz_questions` AS q
              ON ua.`QuestionId` = q.`id`
            GROUP BY ua.`UserId`, q.Category
         ) AS x
    JOIN wp_quiz_users AS u
      ON u.Id = x.UserId

并围绕它积累。

(但是,既然我看到了其他答案,我会很懒,而不是完成这个想法。)

嗯...我想知道我的方法 - 或其他方法 - 是否会因为等待太晚而导致SUMs膨胀GROUP BY