使用子查询重写MySQL查询以进行连接

时间:2010-10-25 11:04:13

标签: mysql join query-optimization subquery

我编写了一个相当复杂的SQL查询来获取动物采样数据库中动物的一些统计数据。此查询包含许多子查询,我现在想看看是否可以以任何方式重写此查询以使用连接而不是子查询。我有一个暗淡的想法,这可能会减少查询时间。 (现在在mac mini上大约23秒)。

以下是查询:

SELECT COUNT(DISTINCT a.AnimalID), TO_DAYS(a.VisitDate) AS day, 
   DATE_FORMAT(a.VisitDate, '%b %d %Y'), a.origin, 
   (
    SELECT COUNT(DISTINCT a.AnimalID)
           FROM samples AS a 
                JOIN
                custom_animals AS b 
                ON a.AnimalID = b.animal_id
                WHERE
                     b.organism = 2
                     AND
                         TO_DAYS(a.VisitDate) = day
    ) AS Goats, 
    (
     SELECT COUNT(DISTINCT a.AnimalID) 
            FROM samples AS a 
                 JOIN custom_animals AS b 
                 ON a.AnimalID = b.animal_id 
                 WHERE
                      b.organism = 2
                      AND 
                         b.sex = 'Female'
                      AND
                         TO_DAYS(a.VisitDate) = day
    ) AS GF,
    (
     SELECT COUNT(DISTINCT a.AnimalID) 
            FROM samples AS a 
                 JOIN custom_animals AS b 
                 ON a.AnimalID = b.animal_id 
                 WHERE 
                      b.organism = 3
                      AND
                         b.sex = 'Female'
                      AND
                         TO_DAYS(a.VisitDate) = day
    ) AS SF
    FROM
        samples AS a 
        JOIN custom_animals AS b 
        ON a.AnimalID = b.animal_id 
        WHERE
             project = 5
             AND
                AnimalID LIKE 'AVD%'
        GROUP BY
                TO_DAYS(a.VisitDate);

感谢ksogor我的查询现在更快了;

SELECT  DATE_FORMAT(s.VisitDate, '%b %d %Y') AS date,
    s.origin,
    SUM(IF(project = 5 AND s.AnimalID LIKE 'AVD%', 1, 0)) AS sampled_animals, 
    SUM(IF(ca.organism = 2, 1, 0)) AS sampled_goats,
    SUM(IF(ca.organism = 2 AND ca.sex = 'Female', 1, 0)) AS female_goats,
    SUM(IF(ca.organism = 3 AND ca.sex = 'Female', 1, 0)) AS female_sheep
FROM samples s JOIN custom_animals ca ON s.AnimalID = ca.animal_id
GROUP BY date;

我仍然需要让这个查询选择不同的s.AnimalID,尽管现在它计算我们从这些动物而不是动物本身采集的样本。有人有任何想法吗?


ksogor获得更多帮助之后,我现在有了一个很棒的问题:

SELECT  DATE_FORMAT(s.VisitDate, '%b %d %Y') AS date,
    s.origin,
    SUM(IF(project = 5 AND s.AnimalID LIKE 'AVD%', 1, 0)) AS sampled_animals, 
    SUM(IF(ca.organism = 2, 1, 0)) AS sampled_goats,
    SUM(IF(ca.organism = 2 AND ca.sex = 'Female', 1, 0)) AS female_goats,
    SUM(IF(ca.organism = 3 AND ca.sex = 'Female', 1, 0)) AS female_sheep
FROM (
    SELECT DISTINCT AnimalID AS AnimalID,
           VisitDate,
           origin,
           project
           FROM samples
) s 
JOIN custom_animals ca ON s.AnimalID = ca.animal_id
GROUP BY date;

1 个答案:

答案 0 :(得分:2)

您可以使用ifcase语句,如下所示:

SELECT  SUM(if(project = 5 AND AnimealID LIKE 'AVD%', 1, 0)) AS countbyproj, 
        TO_DAYS(s.VisitDate) AS day, 
        DATE_FORMAT(s.VisitDate, '%b %d %Y') AS date,
        s.origin,
        SUM(if(ca.organism = 2, 1, 0)) AS countGoats,
        SUM(if(ca.organism = 2 AND ca.sex = 'Female', 1, 0)) AS countGF,
        SUM(if(ca.organism = 3 AND ca.sex = 'Female', 1, 0)) AS countSF
FROM samples s JOIN custom_animals ca ON s.AnimalID = ca.animal_id
GROUP BY TO_DAYS(a.VisitDate);

我无法检查查询,我不知道您期望的结果以及您拥有的表/关系,所以这只是一个有想法的示例。

如果您需要每天计算unque AnimealID:

SELECT SUM(byproj) AS countbyproj,
        day,
        date,
        origin,
        SUM(Goats) AS countGoats,
        SUM(GF) AS countGF,
        SUM(SF) AS countSF
FROM (
    SELECT  s.AnimealID,
            if(project = 5 AND AnimealID LIKE 'AVD%', 1, 0) AS byproj, 
            TO_DAYS(s.VisitDate) AS day, 
            DATE_FORMAT(s.VisitDate, '%b %d %Y') AS date,
            s.origin,
            if(ca.organism = 2, 1, 0)) AS Goats,
            if(ca.organism = 2 AND ca.sex = 'Female', 1, 0) AS GF,
            if(ca.organism = 3 AND ca.sex = 'Female', 1, 0) AS SF
    FROM samples s JOIN custom_animals ca ON s.AnimalID = ca.animal_id
    ) dataset
GROUP BY dataset.day, dataset.AnimealID;