MySQL:日志摘要查询

MySQL:日志摘要查询,mysql,group-by,Mysql,Group By,我的CMS系统中有一个模块,允许网站显示广告。它记录视图和单击。我用来汇总日志的查询执行得很差 以下是查询: SELECT `a`.`id`, `a`.`active`, `a`.`static`, `a`.`position`, `a`.`file`, `a`.`title`, `a`.`url`, COUNT(DISTINCT `lv`.`id`) AS `views`, COUNT(DISTINCT `lc`.`id`) AS

我的CMS系统中有一个模块,允许网站显示广告。它记录视图和单击。我用来汇总日志的查询执行得很差

以下是查询:

SELECT `a`.`id`,
    `a`.`active`,
    `a`.`static`,
    `a`.`position`,
    `a`.`file`,
    `a`.`title`,
    `a`.`url`,
    COUNT(DISTINCT `lv`.`id`) AS `views`,
    COUNT(DISTINCT `lc`.`id`) AS `clicks` 
FROM `ads` AS `a` 
LEFT JOIN `ad_log` AS `lv` 
    ON `lv`.`ad_id` = `a`.`id` 
    AND `lv`.`type` = 'view' 
    AND `lv`.`created` BETWEEN '2011-01-01 00:00:00'
        AND '2011-12-31 23:59:59' 
LEFT JOIN `ad_log` AS `lc` 
    ON `lc`.`ad_id` = `a`.`id` 
    AND `lc`.`type` = 'click' 
    AND `lc`.`created` BETWEEN '2011-01-01 00:00:00' 
        AND '2011-12-31 23:59:59' 
GROUP BY `a`.`id` 
ORDER BY `a`.`static` DESC,
    `a`.`position` ASC,
    `a`.`title` ASC 
ad_log
表在
ad_id
type
列上有两列索引。当我查看探查器结果时,它正在使用该索引。一个不同的索引会更有效吗


更新

在测试了不同的指数组合后,目前的指数组合似乎是最好的。也许有更好的方法来编写查询

下面是解释选择SQL\u NO\u缓存的屏幕截图…:


解决方案

我已经接受了,但这是我提出的问题。它的性能仅略低于:


最佳性能

受以下因素启发,此查询具有更好的性能:

SELECT `a`.`id`,
    `a`.`active`,
    `a`.`static`,
    `a`.`position`,
    `a`.`file`,
    `a`.`title`,
    `a`.`url`,
    SUM(CASE WHEN `l`.`type` = 'view' THEN 1 ELSE 0 END) AS `views`,
    SUM(CASE WHEN `l`.`type` = 'click' THEN 1 ELSE 0 END) AS `clicks` 
FROM `ads` AS `a` 
LEFT JOIN `ad_log` AS `l`
    ON `a`.`id` = `l`.`ad_id`
    AND `l`.`created` BETWEEN '2011-11-01 00:00:00'
        AND '2011-11-30 23:59:59'
GROUP BY `a`.`id`
ORDER BY `a`.`static` DESC,
    `a`.`position` ASC,
    `a`.`title` ASC 

您可以索引
ad\u id、键入和创建
,以获得更快的结果

这是一本关于如何为联接编制索引的好书。也请阅读其他案例,它们很有帮助


您可以通过索引列来进一步优化它,但请记住,索引越多,您的写入速度就会越慢。

您可以索引
ad\u id、键入和创建
,以获得更快的结果

这是一本关于如何为联接编制索引的好书。也请阅读其他案例,它们很有帮助


您可以通过为列编制索引来进一步优化它,但请记住,索引越多,您的写入速度就会越慢。

另一种方法可能是将sub select作为联接,按日期范围预先聚合所有视图/单击,然后联接到所有可用的广告

SELECT 
      a.id,
      a.active,
      a.static,
      a.position,
      a.file,
      a.title,
      a.url,
      COALESCE( PreAgg.CntViews, 0 ) views,
      COALESCE( PreAgg.CntClicks, 0 ) clicks
   FROM
      ads AS a 
      LEFT JOIN 
         ( select lv.ad_id,
                  sum( if( lv.type = 'view', 1, 0 )) as CntViews,
                  sum( if( lv.type = 'click', 1, 0 )) as CntClicks
              from
                 ad_log lv
              where
                     lv.type in ( 'view', 'click' )
                 and lv.created between '2011-01-01 00:00:00'
                                    AND '2011-12-31 23:59:59' 
              group by
                  lv.ad_id ) PreAgg
        on A.ID = PreAgg.Ad_ID

如果您在Ad_日志表上有一个基于(type、created、Ad_id)的索引,则速度可能会更快。。。这样,对于每个“类型”都将进行分组,然后在每个类型中,向右跳转到日期范围。所以它应该只需要点击索引的两个部分。。。从/到“查看”和从/到“单击”。而不是每个“广告id”,然后检查类型,然后检查日期…

另一种方法可能是让sub select作为联接,按日期范围预先聚合所有视图/点击,然后联接到所有可用的广告

SELECT 
      a.id,
      a.active,
      a.static,
      a.position,
      a.file,
      a.title,
      a.url,
      COALESCE( PreAgg.CntViews, 0 ) views,
      COALESCE( PreAgg.CntClicks, 0 ) clicks
   FROM
      ads AS a 
      LEFT JOIN 
         ( select lv.ad_id,
                  sum( if( lv.type = 'view', 1, 0 )) as CntViews,
                  sum( if( lv.type = 'click', 1, 0 )) as CntClicks
              from
                 ad_log lv
              where
                     lv.type in ( 'view', 'click' )
                 and lv.created between '2011-01-01 00:00:00'
                                    AND '2011-12-31 23:59:59' 
              group by
                  lv.ad_id ) PreAgg
        on A.ID = PreAgg.Ad_ID

如果您在Ad_日志表上有一个基于(type、created、Ad_id)的索引,则速度可能会更快。。。这样,对于每个“类型”都将进行分组,然后在每个类型中,向右跳转到日期范围。所以它应该只需要点击索引的两个部分。。。从/到“查看”和从/到“单击”。然后检查类型、日期,而不是每个“ad id”…

出于兴趣,您是否也可以发布EXPLAIN SELECT SQL\u NO\u CACHE…..的输出。。。。。您的其余查询将发布解释查询的输出。@AdrianCornish和@daking963-我已经发布了
explain SELECT SQL\u NO\u缓存的屏幕截图
results出于兴趣,您是否也可以发布explain SELECT SQL\u NO\u缓存的输出。。。。。查询的其余部分将显示解释查询的输出。@AdrianCornish和@daking963-我已经发布了
explain-SELECT-SQL\u-NO\u缓存
结果的屏幕截图。在进一步测试后,将
created
添加到索引中会进一步降低查询速度。在进一步测试后,将
created
添加到索引中会进一步降低查询速度。我正在为每个计数列设计一个具有子选择的解决方案,但我喜欢预聚合的想法。我的子选择解决方案比我发布的查询快得多,但这似乎更快了。@Sonny,这是通过索引优化内部查询的另一种可能性。请参阅评论我尝试添加不同的索引,但它继续在预聚合部分使用外键索引。我正在为每个计数列使用子选择的解决方案,但我喜欢预聚合的想法。我的子选择解决方案比我发布的查询快得多,但这似乎更快了。@Sonny,这是通过索引优化内部查询的另一种可能性。请参阅commentI,我尝试添加不同的索引,但它继续使用外键索引作为预聚合部分。