【问题标题】:Help with MYSQL Query Aggregating counts (alternative to three sub-queries)帮助 MYSQL 查询聚合计数(替代三个子查询)
【发布时间】:2011-11-05 08:32:10
【问题描述】:

我正在尝试按年份从我的统计表和组中输出总内容视图...我的统计表是 INNODB 并且有 8M 行并且还在增长...

该表本质上是ID、DATE、MAKE、IP、REFERRER(id、date、make上的索引)

每个条目都有一个自动递增的 ID、条目日期 YYYY-MM-DD HH:MM:SS,以及“索尼”、“松下”等产品品牌...

我正在尝试进行一个不会杀死我的服务器的查询,该查询总结了每年的总内容浏览量,并按从最多浏览到最少浏览的顺序显示它们...(对于 2011 年),以便我可以使用将这些数据填充到今年与过去几年比较的 JS 图表中。我可以通过多个查询和遍历 PHP 中的数组来做到这一点,但我认为应该有一种方法可以在一个查询中得到这个,但如果我能弄清楚的话,那就见鬼了。

有什么想法吗?另外,我是不是最好进行三个独立的查询并在 PHP 中处理结果,或者我可以将其合并到一个查询中,从而提高 MYSQL 的效率。

我想看到的输出(虽然我似乎无法做到这一点),很简单

MAKE 2009总计 2010总计 2011总计 ---- --------- --------- --------- 松下 800 2345 3456 索尼 998 5346 2956 合资公司 1300 1234 1944

假设我的表中有从 2009 年到现在的数据,我需要我的数组在每个 make 中包含一行...

任何帮助将不胜感激...我很惊讶分析工具返回的结果如此之快,而我在 4x Quad-core XEON RAID mysql 服务器上需要大约 75 秒...此统计表未写入但是每天一次转储前一天的统计数据,所以我不确定为什么我的 3 sep 查询如此缓慢......因此我的问题......也许单个查询不会更快?

无论如何,我们将不胜感激任何帮助,并欢迎有关从通用视图统计表中加快统计查询的意见!

【问题讨论】:

  • 您可以提交您使用的查询吗?
  • “内容视图”如何存储在表中?

标签: mysql aggregation


【解决方案1】:

我做了一个观察。您的查询是按年份请求的。你应该做两件事:

  1. 存储年份
  2. 创建更好的索引(产品、年份)

你可以这样做:

CREATE TABLE stats_entry_new LIKE stats_entry;
ALTER TABLE stats_entry_new ADD COLUMN entryyear SMALLINT NOT NULL AFTER date;
ALTER TABLE stats_entry_new ADD INDEX product_year_ndx (product,year);
ALTER TABLE stats_entry_new DISABLE KEYS;
INSERT INTO stats_entry_new
SELECT ID, DATE,YEAR(date),product,IP,REFERRER FROM state_entry;
ALTER TABLE stats_entry_new ENABLE KEYS;
ALTER TABLE stats_entry RENAME stats_entry_old;
ALTER TABLE stats_entry_new RENAME stats_entry;

现在查询看起来像这样:

SELECT A.product,B.cnt "2009Total",C.cnt "2010Total",D.cnt "2011Total"
FROM
(SELECT DISTINCT product FROM stats_entry) A
INNER JOIN 
(SELECT product,COUNT(1) cnt FROM stats_entry WHERE entryyear=2009 GROUP BY product) B
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry WHERE entryyear=2010 GROUP BY product) C
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry WHERE entryyear=2011 GROUP BY product) D
USING (product);

现在公平地说,如果您不想在表中添加年份,那么您仍然需要创建索引

ALTER TABLE stats_entry ADD INDEX product_date_ndx (product,date);

您的查询现在看起来像这样

SELECT A.product,B.cnt "2009Total",C.cnt "2010Total",D.cnt "2011Total"
FROM
(SELECT DISTINCT product FROM stats_entry) A
INNER JOIN 
(SELECT product,COUNT(1) cnt FROM stats_entry
WHERE date >= '2009-01-01 00:00:00'
AND date <= '2009-12-31 23:59:59'
GROUP BY product) B
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry
WHERE date >= '2010-01-01 00:00:00'
AND date <= '2010-12-31 23:59:59'
GROUP BY product) C
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry
WHERE date >= '2011-01-01 00:00:00'
AND date <= '2011-12-31 23:59:59'
GROUP BY product) D
USING (product);

试试看!!!

【讨论】:

  • 很好,(make,year) 上的复合索引将是这里最有用的索引。可能需要LEFT JOIN 而不是INNER JOIN 来包含某些年份丢失的产品。
【解决方案2】:
SELECT make,year(date) as year,sum(views) 
FROM `stats ` 
group by make,year

o/p :

MAKE         year        sum
-------       -------    ---------  
Panasonic    2009        800     
Panasonic    2010        2345    
Panasonic    2011        3456

....

您可以稍后在 php 端进行隔离。

或:

select make ,group_concat(cast(yr_views as char)) as year_views
from (SELECT make,concat(year(date),':',sum(views)) as yr_views
FROM `stats` 
group by make,year(date))as make_views
group by make

o/p:

make             year_views
------         ---------------
panasonic   2009:800,2010:2345,2011:3456
...

稍后,在 PHP 级别爆炸并得到结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 2011-07-19
    • 2011-04-28
    相关资源
    最近更新 更多