Соответствие даты и интерполяция в PHP - PullRequest
0 голосов
/ 04 августа 2011

Prelude: У меня большой набор данных с несколькими сотнями тысяч записей, хранящихся в базе данных MySQL. Значительно упрощенный, каждая строка имеет поле даты и времени для хранения даты и времени, когда был сделан телефонный звонок, и целочисленное поле для хранения продолжительности вызова.


Сценарий: Я занят написанием интерполяционной функции в PHP, которая генерирует диапазон дат, разделенных предварительно рассчитанным интервалом. Каждая сгенерированная дата сохраняется в ассоциативном массиве с датой, используемой в качестве ключа, и каждое значение инициализируется равным 0. Затем сценарий запрашивает в базе данных список записей и пытается сопоставить запись даты-времени с ближайшей датой в пред. сгенерированный ассоциативный массив. Когда найдено самое близкое совпадение, оно просто добавляет длительность вызова к существующему значению массива с этим индексом.


Пример сгенерированного ассоциативного массива:

$array    =   array(  "2011-01-01 09:00:00" => 0,
                      "2011-01-01 09:30:00" => 0,
                      "2011-01-01 10:00:00" => 0,
                      "2011-01-01 10:30:00" => 0,
                      "2011-01-01 11:00:00" => 0,
                      "2011-01-01 11:30:00" => 0,
                      "2011-01-01 12:00:00" => 0
                   )

В приведенном выше примере диапазон дат создается с интервалом в 30 минут.


Пример записей из базы данных MySQL:

+---------------------+----------+
| datetime            | duration |
+---------------------+----------+
| 2011-01-01 09:02:26 |        1 |
| 2011-01-01 09:14:51 |        1 |
| 2011-01-01 10:40:33 |      549 |
| 2011-01-01 11:10:27 |       38 |
| 2011-01-01 11:31:50 |       82 |
+---------------------+----------+

Теперь необходимо сопоставить каждую из этих записей с ближайшим ключом даты и времени из предварительно сгенерированного массива, указанного выше, и к значению duration, добавленному к существующему значению совпадения.


Проблема: Достаточно просто построить два вложенных цикла for, чтобы просмотреть записи из базы данных, а затем линейно прогнать ассоциативный массив, чтобы найти совпадение, но это крайне неэффективно и становится проблематичным для больших наборов данных (подумайте, сортировка пузырьков, вот что это будет примерно эквивалентно). Немного лучший подход заключается в линейном цикле записи записей из базы данных, а затем итерации по массиву в виде двоичного дерева, что, безусловно, намного более эффективно и возможно, поскольку оба массива отсортированы в хронологическом порядке.


Вопрос: Есть ли более эффективный способ обработки сопоставления дат, чем, как я описал в приведенной выше проблеме?

Ответы [ 2 ]

3 голосов
/ 04 августа 2011

Как насчет деления UNIX_TIMESTAMP() даты на 30 * 60 секунд (30 минут) и использования ROUND() для целого числа. Затем используйте GROUP BY, чтобы сгруппировать их, и, наконец, SUM(), чтобы суммировать длительности.

SELECT SUM(duration), ROUND(UNIX_TIMESTAMP(datetime) / (30 * 60)) FROM table GROUP BY ROUND(UNIX_TIMESTAMP(datetime) / (30 * 60))
1 голос
/ 04 августа 2011

Ваш текущий алгоритм (если я вас правильно понимаю) выглядит так:

  1. Получить все записи
  2. Сравните дату и время каждой записи с ключом массива
  3. Увеличение суммы соответствующего значения массива на основе записи

Более эффективным методом может быть:

  1. Запрос суммы длительностей для всех записей, соответствующих данному подмножеству времени
  2. Вставьте сумму в массив с помощью соответствующего ключа

Это позволяет MySQL предоставлять оптимизированную математическую логику и уменьшает количество итераций массива, требуемых вашим сценарием. Вы увеличите количество запросов к базе данных, но сравнительный анализ покажет вам, стоит ли идти на компромисс.

...