Я ищу советы по лучшей практике, как ускорить запросы и в то же время минимизировать накладные расходы, необходимые для вызова функций 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(...){ /* 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", ..);
}
Каковы мои идеи до сих пор? Добавьте дополнительные/избыточные столбцы (INTEGER) за день (20091212), месяц (200912), неделю (200942) и год (2009). Таким образом, я могу избавиться от всех ненужных запросов в цикле for. Однако я все еще сталкиваюсь с проблемой, чтобы очень быстро вычислить все даты, которые не имеют эквивалента в базе данных. Один из способов просто переместить проблему может состоять в том, чтобы позволить MySQL выполнить задание и просто использовать один большой запрос (рассчитать все даты/использовать функции даты MySQL) с левым соединением (данными). Было бы разумным позволить MySQL взять дополнительную нагрузку? В любом случае я не хочу использовать все эти mktime/date в цикле for. Поскольку у меня есть полный контроль над табличной планировкой и кодом, даже приветствуются предложения с серьезными изменениями!
Update
Благодаря 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;
Спасибо за быстрый ответ! Мне потребуется некоторое время, чтобы проверить вашу идею, потому что мне нужно переключиться с INTEGER на DATETIME, чтобы успешно использовать DATE_FORMAT. Однако это выглядит многообещающе. Если я не ошибаюсь, чего-то не хватает, как мне получить все эти даты без записей в таблице? Например: у меня есть данные за 2009-10 и 2009-11 годы, но 2009-12 пуст, но должен быть заметен тем не менее ..должен ли я вернуться к функциям PHP для этого или есть ли для этого элегантное решение mysql? – merkuro
@merkuro: Вы можете выводить только данные * там *. Отсутствующие записи не будут волшебным образом появляться. Если вам нужно иметь запись за каждый день года, сделайте таблицу календаря и сделайте внешнее соединение против этого. Такая таблица должна быть создана/заполнена только один раз, и ей требуется всего 365 рядов в год. Таким образом, любые «пробелы» исчезнут на выходе. – Tomalak
@Tomalak Вы имеете в виду, что в установках MySQL нет встроенного волшебника? Честно говоря, с какой целью были ваши смешные комментарии? Я уже упоминал о возможности использования левого соединения, хотя я вижу потенциальную проблему с производительностью в этом решении из-за увеличения использования диска. В любом случае я надеялся, что кто-то придумает хороший диапазон/массив, как функция, которую я упустил. – merkuro