mysql:RIGHT JOIN查询涉及日历表的速度问题

时间:2012-04-26 13:29:18

标签: mysql database-design 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  

2 个答案:

答案 0 :(得分:1)

一些想法......

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

编辑:澄清一下,如何调用查询?即是否有一些程序(您正在开发)访问数据库,运行查询并显示结果?如果是这样,我建议让这个程序在演示之前处理结果。

其次,如果你致力于'加入',你真的应该在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函数以进行连接 - 这将很快使查询变得缓慢。这也允许您在 date time 列上添加索引,这也可以提高连接的性能(鉴于您当前的数据库设计,我不是对actioned_date上的索引感到惊讶没有帮助 - 由于DATE()功能,如果您使用EXPLAIN列上的索引重新运行actioned_date,我宁愿期望这样做就目前而言,它不会在all_griefs_tbl上使用此索引显示它。)

第四,您可能想要考虑在all_griefs_tbl.actioned_status中存储哪些类型的信息。这可以用布尔值替换吗?这在存储和处理数据方面都会更有效。 (尽管如此,这取决于您的数据库设计。)

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

答案 1 :(得分: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行的表。