MySQL:日志摘要查询
我的CMS系统中有一个模块,允许网站显示广告。它记录视图和单击。我用来汇总日志的查询执行得很差 以下是查询: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
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,我尝试添加不同的索引,但它继续使用外键索引作为预聚合部分。