2012-04-26 53 views
0

更新:它似乎是问题(如各种人所述)正在将日期时间字段更改为查询中的日期字段。mysql:RIGHT JOIN查询涉及日历表的速度问题

使用DATE(all_griefs_tbl.actioned_date太慢了,是否有一种更快的方法,但不会将actioned_date更改为日期字段或将其拆分为日期和时间字段?

我有2个表,一个用的是有一个状态和日期时间字段和记录负载另一种是从2008年日期2015年

日历表我想离开是每一个日期在一个时间段和已经被“接受”每一天的记录数 - 即使计数为零 - 这应该是这样的:

| Date  | number_accepted | 
---------------------------- 
2012-03-01  723 
2012-03-02  723 
2012-03-03  1055 
2012-03-04  1069 
2012-03-05  0 
2012-03-06  615 
2012-03-07  0 
2012-03-08  1072 
2012-03-09  664 
2012-03-10  859 
2012-03-11  0 
2012-03-12  778 
2012-03-13  987 

我试过以下,但也仅仅是快足够少量的数据样本(-1000行)。我需要的东西是非常适用于至少600K行

SELECT calendar.datefield AS Date, 
     COUNT(all_griefs_tbl.actioned_status) AS total_griefs 
FROM all_griefs_tbl 
RIGHT JOIN calendar 
    ON (DATE(all_griefs_tbl.actioned_date) = calendar.datefield) 
    AND all_griefs_tbl.actioned_status = 'accepted' 
WHERE calendar.datefield < CURDATE() 
GROUP BY calendar.datefield 

感谢

编辑:根据要求

id select_type  table   type possible_keys  key    key_len  ref  rows Extra 
1 SIMPLE   calendar  range PRIMARY   PRIMARY   3   NULL 1576 Using where; Using index 
1 SIMPLE   all_griefs_tbl ref  actioned_status actioned_status 153   const 294975 
+0

请提供执行计划(在选择之前添加解释时的输出) – 2012-04-26 13:38:59

+0

您的日历表中包含每个日期。你从2008年开始每天都会去现在的日期吗?您可能会更好地使用每天计数的汇总表,而不是每次重新计算。 – DRapp 2012-04-26 16:29:10

+0

这个想法是获取highstocks图表的数据 - http://www.highcharts.com/,因此从2008年到现在将是理想的。只要至少有1个,我就可以每天获得计数......如果我无法实现这个目标,我想这将会回落。 – eek 2012-04-26 17:01:12

回答

1

的一点想法...

首先,尽管执行计划你声明你想在db查询中返回没有任何值的日子,我实际上会对结果集进行检查,无论它在哪里处理。无论何时进行连接,都会使查询变得更加复杂,并需要更多内存来处理它们。在这种情况下,我不会认为您使用日历表作为关系数据库的特别有效的用途。

编辑:澄清,如何调用查询?即是否有一些程序(您正在开发)访问数据库,运行查询并显示结果?如果是这样,我建议让这个程序在演示前处理结果。其次,如果你承诺'加入',你真的应该在all_griefs_tbl.actioned_date上有一个索引,因为这是你进行连接的列。或者,您可以在calendar.datefield上指定外键。

三,您是否需要使用功能DATE(all_griefs_tbl.actioned_date)?这不是已经约会吗? (不知道你的数据类型,但如果这和calendar.datefield不是相同的数据类型,这看起来像不好的数据库设计。)

编辑:根据你所说的,你可能想分裂成all_griefs_tbl.actioned_date两列日期列all_griefs_tbl.actioned_date和时间戳列all_griefs_tbl.actioned_time。目前,您在all_griefs_tbl的每一行上都运行这个DATE()函数,以便进行连接 - 这将很快导致查询缓慢。这也可以让你在日期时间列上添加一个索引,这也会提高连接的性能(鉴于你当前的数据库设计,我并不感到惊讶actioned_date索引没有帮助 - 我宁可期待,因为DATE()函数,如果您重新运行EXPLAINactioned_date列的索引,因为它目前代表,它不会显示它使用此索引all_griefs_tbl。)

第四,您可能要考虑在all_griefs_tbl.actioned_status中存储了哪些类型的信息。可以用布尔值替换吗?这在存储和处理数据时会更有效率。 (虽然这又取决于你的数据库设计。)

编辑:你可以考虑改变all_griefs_tbl.action_status到一个更小的数据类型 - 我期望它目前是一个varchar,但你可以很容易地改变这个单一(或小)char数据类型,甚至是一些布尔人。但是,我不认为这会成为主要的性能开销,而且根据项目的需要,它确实是一个更为复杂的数据库设计决策。

+0

感谢您的回复。我使用的是日历表,所以我可以在一段时间内得到所有日期,以免丢失。如果有更好的方法,我很乐意听到它。我没有承诺加入,我只是不知道另一种方式去做。我确实在all_griefs_tbl.actioned_date上有了一个索引,但它似乎没有太大区别。 calendar.datefield是日期字段,all_griefs_tbl.actioned_date是日期时间字段。这是唯一的区别。有几种不同的状态,all_griefs_tbl.actioned_status可能是:接受,排队,锁定 – eek 2012-04-26 15:10:08

+0

我想实现这里完成的工作:http://www.richnetapps.com/using-mysql-generate-daily-sales-报告填补的差距/不同之处在于我在计算时间范围内的行数而不是总结数值。 – eek 2012-04-26 15:24:16

+0

@eek - 我在评论中添加了评论。 – amaidment 2012-04-26 15:36:24

1

我建议从日期时间分割你的actioned_date成2个独立的日期和时间列,可以说actioned_dateactioned_time所以你可以

ON (DATE(all_griefs_tbl.actioned_date) = calendar.datefield) 

改变你的第一个连接条件

ON (all_griefs_tbl.actioned_date = calendar.datefield) 

和添加索引

ALTER TABLE all_griefs_tbl ADD INDEX g_status_date(actioned_status, actioned_date, actioned_time); 

它可能会使您的查询即时为600k行的表。

+0

这是我认为会起作用的一种解决方案,但是我想知道的是,如果有另一种方法而不是DATE(),那么我可以使用它更快?将其拆分为2个独立的列将是最后的手段。 – eek 2012-04-26 17:20:32

+0

+1分拆建议 – eek 2012-04-26 17:33:37

+0

拆分将允许使用提到的索引也为该组提供,这将有所不同,谈论msecs而不是秒。 – piotrm 2012-04-26 17:39:44