0

更新:似乎问题(如各种人所述)是将日期时间字段更改为查询中的日期字段。

使用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  
4

2 回答 2

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。目前,您DATE()在每一行上运行此函数all_griefs_tbl以进行连接 - 这将很快使查询变得迟缓。这也将允许您在日期时间列上添加索引,这也将提高连接的性能(鉴于您当前的数据库设计,我对索引actioned_date没有帮助并不感到惊讶 - 我宁愿期待那,由于该DATE()功能,如果您使用当前列EXPLAIN上的索引重新运行actioned_date,它不会使用此索引显示它all_griefs_tbl。)

第四,您可能需要考虑存储在all_griefs_tbl.actioned_status. 这可以用布尔值代替吗?这将更有效地存储和处理数据。(虽然同样,这取决于您的数据库设计。)

编辑:您可以考虑更改all_griefs_tbl.action_status为较小的数据类型 - 我希望它当前是 varchar,但您可以轻松地将其更改为单个(或小)char 数据类型,甚至更改为多个布尔值。但是,我不认为这会成为主要的性能开销,并且实际上是一个更复杂的数据库设计决策,具体取决于您的项目需求。

于 2012-04-26T14:58:45.560 回答
1

我建议将您的actioned_datefrom datetime 拆分为 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 行的表立即进行查询。

于 2012-04-26T16:41:55.137 回答