2015-07-17 1 views
1

Я работаю над приложением генерировать накопление и Burndown диаграмму в MySQL/PHP, который я использую для создания с помощью NVD3.jsПроизводительность MySQL - как ускорить запрос для диаграммы построения/выгорания?

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

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

Как я могу сгенерировать эти данные быстрее?

Призывая Code

public function burnupAction() 
    { 
     $actionItemTable = $this->getActionItemTable(); 
     $burnUp = array('TotalActionItems' => $actionItemTable->getBurnup('AssignedDate'), 
         'ECDItems' => $actionItemTable->getBurnup('ECD'), 
         'OriginalDueItems' => $actionItemTable->getBurnup('DueDate'), 
         'ActualOpenItems' => $actionItemTable->getBurnup('ClosedDate')); 
     $this->response->setContent(json_encode($burnUp)); 
     return $this->response; 
    } 

Build Up Chart Код

for ($y = $minYear; $y <= $maxYear; $y++) 
{ 
     if ($y == $minYear) 
      $startMonth = $minMonth; 
     else 
      $startMonth = 1; 

     if ($y == $maxYear) 
      $finishMonth = $maxMonth; 
     else 
      $finishMonth = 12; 


     for ($m = $startMonth; $m <= $finishMonth; $m++) 
     {      
      if ($m < 10) 
      { 
       $month = "0$m"; 
      } 
      else 
      { 
       $month = "$m"; 
      } 
      $monthStr = $this->getMonth($m); 


      for ($d = 1; $d <= 31; $d++) 
      { 
        if ($d< 10) 
        { 
         $day = "0$d"; 
        } 
        else 
        { 
         $day = "$d"; 
        } 

        $dt = "$monthStr $day $y"; 
        $start = "$y-$month-$day"; 
        $end = "$y-$month-$day"; 

        $where = $this->filterString(); 
        $filtered = "SELECT * FROM actionitems " . $where; 

        if ($field == 'AssignedDate') 
        { 
         array_push($subsel, "(select '$dt' as AssignedDate, sum(case when AssignedDate Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from ($filtered) s)"); 
        } 
        if ($field == 'ECD') 
        { 
         array_push($subsel, "(select '$dt' as ECD, sum(case when ECD Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from ($filtered) s)"); 
        } 
        if ($field == 'DueDate') 
        { 
         array_push($subsel, "(select '$dt' as DueDate, sum(case when DueDate Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from ($filtered) s)"); 
        } 
        if ($field == 'ClosedDate') 
        { 
         array_push($subsel, "(select '$dt' as ClosedDate, sum(case when ClosedDate Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from ($filtered) s)"); 
        } 
      } 
     } 
    } 

    if (count($subsel) == 0) 
     return array(); 


    $sub = join(" union all ", $subsel); 

    if ($field == 'AssignedDate') 
    { 
     $sql = "select AssignedDate, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t"; 
    } 
    if ($field == 'ECD') 
    { 
     $sql = "select ECD, NumActionItems as ECDItems, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t"; 
    } 
    if ($field == 'DueDate') 
    { 
     $sql = "select DueDate, NumActionItems as OriginalDueItems, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t"; 
    } 
    if ($field == 'ClosedDate') 
    { 
     $sql = "select ClosedDate, NumActionItems as AcutalClosedItems, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t"; 
    } 

Сформированные тележки (раскачки сверху/Burndown снизу)

Buildup/Burdown Charts

+0

Предполагаю, что у вас есть указатели на даты? Вы можете сохранить значения @csum. Также вы можете перечислить 1 или 2 полных запроса в SQL. Я вижу, что делает ваш код, но генерировать его в моей голове не является оптимальным, чтобы дать рекомендации относительно производительности. –

+0

Пожалуйста, см. Ниже: https://jsfiddle.net/06y6bz71/ – Vahe

+0

Благодарим за быстрый ответ. По-моему, я еще не установил индексы для моего запроса, но если это поможет, я могу ускорить его, добавив его. – Vahe

ответ

1

Основная часть вашего запроса заключается в следующем:

SELECT 'Mar 01 2015' AS AssignedDate, 
      Sum(CASE 
        WHEN assigneddate BETWEEN '2015-03-01' AND '2015-03-01' 
       THEN 1 
        ELSE 0 
       end)  AS 'NumActionItems' 
    FROM (SELECT * 
      FROM actionitems) s; 

Этот запрос имеет 1 недостаток: За сегодняшний день таблица actionitems сканируется.

Чтобы улучшить этот запрос можно записать в виде:

SELECT 'Mar 01 2015' AS AssignedDate, 
      COUNT(*) AS 'NumActionItems' 
    FROM actionitems 
    WHERE assigneddate BETWEEN '2015-03-01' AND '2015-03-01'; 

Это еще не очень, поэтому требуется следующий шаг: Альтернативой для всех дат может быть:

SELECT assigneddate, 
      COUNT(*) AS 'NumActionItems' 
    FROM actionitems 
    WHERE assigneddate BETWEEN '2015-03-01' AND '2015-03-30' 
    GROUP BY assigndate; 

Это даст вам «NumActionItems» за дату.

Добавление @csum в качестве внешнего запроса:

SELECT assigneddate, 
    (@csum := @csum + numactionitems) AS TotalActionItems 
FROM ( SELECT assigneddate, 
      COUNT(*) AS 'NumActionItems' 
    FROM actionitems 
    WHERE assigneddate BETWEEN '2015-03-01' AND '2015-03-30' 
    GROUP BY assigndate) a 

должны дать тот же результат.

Также добавьте индекс:

CREATE INDEX idx_ai_nn_1 ON actionitems(assigneddate); 

Этот индекс будет работать, если диапазон дат вы сканированием таблицы как для < < меньше, чем количество строк вы выбирающие.

+0

Благодарим вас за быстрый ответ.Пусть сделают изменения, и я отчитаю. Кроме того, количество строк на самом деле противоположное, оно намного меньше числа дат, которые я выпускаю. – Vahe

+0

Хорошо, 1 подсказка: Это не возвращает данные для дат, у которых нет данных в базе данных. Поэтому, повторяя этот набор, учтите это. Также сначала проверьте результаты запроса, и они в сеансе mysql: сэкономит вам много времени, если в этом есть ошибка :) –

+0

Благодарим за комментарий, я пытаюсь заставить его производить все даты без какой-либо ценности, который, я думаю, может потребовать сохранения моих основных циклов в моем коде. – Vahe