更新:似乎问题(如各种人所述)正在将日期时间字段更改为查询中的日期字段。
使用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 :(得分: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_date
和actioned_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行的表。