我正在寻找一个最佳实践建议,如何加快查询速度,同时最小化调用date/mktime函数所需的开销。为了简化问题,我正在处理以下表格布局:
CREATE TABLE my_table(
id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
important_data INTEGER,
date INTEGER);
用户可以选择显示1)两个日期之间的所有条目:
SELECT * FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
输出:
10-21-2009 12:12:12, 10002
10-21-2009 14:12:12, 15002
10-22-2009 14:05:01, 20030
10-23-2009 15:23:35, 300
....
2) 按天、周、月、年对输出进行汇总/分组:
SELECT COUNT(*) AS count, SUM(important_data) AS important_data
FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
按月输出的示例:
10-2009, 100002
11-2009, 200030
12-2009, 3000
01-2010, 0 /* <- very important to show empty dates, with no entries in the table! */
....
为了完成选项2),我目前正在使用mktime/date运行一个非常昂贵的for循环,如下所示:
for(...){ /* example for group by day */
$span_from = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i, date("Y", $time_min));
$span_to = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i+1, date("Y", $time_min));
$query = "..";
$output = date("m-d-y", ..);
}
到目前为止,我的想法是什么?为日(20091212)、月(200912)、周(200942)和年(2009)添加额外/冗余列(整数)。这样我就可以消除for循环中所有不必要的查询。然而,我仍然面临着一个问题,就是要非常快速地计算数据库中没有任何等价物的所有日期。解决这个问题的一种方法是让MySQL来完成这项工作,只需使用一个大查询(计算所有日期/使用MySQL日期函数)和一个左连接(数据)。让MySQL承担额外的负载是否明智?无论如何,我不愿意在for循环中使用所有这些mktime/date。因为我可以完全控制表格的布局和代码,所以即使是有重大更改的建议也是受欢迎的!
使现代化
多亏了Greg,我提出了以下SQL查询。但是,使用50行sql语句(使用php构建)仍然让我感到困扰,否则可能会更快、更优雅:
SELECT * FROM (
SELECT DATE_ADD('2009-01-30', INTERVAL 0 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 1 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 2 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 3 DAY) AS day UNION ALL
......
SELECT DATE_ADD('2009-01-30', INTERVAL 50 DAY) AS day ) AS dates
LEFT JOIN (
SELECT DATE_FORMAT(date, '%Y-%m-%d') AS date, SUM(data) AS data
FROM test
GROUP BY date
) AS results
ON DATE_FORMAT(dates.day, '%Y-%m-%d') = results.date;