Страница 1 из 4

Эффективность алгоритма

Добавлено: Пт дек 07, 2012 6:16 pm
Alex
Посмотрел я тут код и у меня возник вопрос. Выходит, что для получения каждой точки он (алгоритм) посылает отдельный SQL запрос. Если на графике 100 точек — это 100 SQL запросов. А если 200 точек, то это 200 SQL запросив. Если 10 графиков — это 2000(!) SQL запросов. Теперь понятно почему всё тормозит по жуткой силе.

Не лучше ли с точки зрения эффективности было бы делать 1 SQL запрос с времени start_time до времени end_time, а потом в цикле формировать DataSet? Вместо 2000 запросов будет всего 10.

Надо то всего написать один запрос и переписать цикл.

Код: Выделить всё

 if ($total>0) {
   $px=0;
   $px_passed=0;
   $dt=date('Y-m-d', $start_time);

   while($start_time<$end_time) {

     $ph=SQLSelectOne("SELECT ID, VALUE FROM phistory WHERE VALUE_ID='".$pvalue['ID']."' AND ADDED<=('".date('Y-m-d H:i:s', $start_time)."') ORDER BY ADDED DESC LIMIT 1");
     if ($ph['ID']) {
       $values[]=(float)$ph['VALUE'];
     } else {
        $values[]=0;
       }

     if ($px_passed>40) {
       if (date('Y-m-d',$start_time) != $dt) {
         $hours[] = date('d/m',$start_time);
         $dt = date('Y-m-d',$start_time);
       } else {
           $hours[] = date('H:i',$start_time);
         }
           $px_passed=0;
     } else {
         $hours[]='';
       }

     $start_time += $period;
     $px += $px_per_point;
     $px_passed += $px_per_point;
   }

   $DataSet->AddPoint($values,"Serie1");  
   $DataSet->AddPoint($hours,"Serie3");  

  } else {

   $DataSet->AddPoint(0,"Serie1");
   $DataSet->AddPoint(0,"Serie3");
  }

Re: Эффективность алгоритма

Добавлено: Пт дек 07, 2012 6:52 pm
sergejey
Абсолютно согласен. Где-то в моём списке задач есть пункт про оптимизацию графиков именно в таком ключе -- один запрос и формирование точек с нужными интервалами уже по имеющейся выборке. Так что либо я со временем до этого пункта дойду, либо кто-то из тех кто может внести изменения в исходники и их прислать ))

Re: Эффективность алгоритма

Добавлено: Пт дек 07, 2012 7:10 pm
Alex
То ли я графики очень люблю, :) то ли чего, но у меня система уже встала. Нажимаем на страничку и 20 секунд ждём отрисовки паршивенького графика. Я конечно попробую переписать этот кусок, но не уверен, что моих познаний будет достаточно. Ау, php программисты! Мы ищем таланты!
:D

Re: Эффективность алгоритма

Добавлено: Сб дек 08, 2012 12:02 pm
Alex
Итак,

выносим SQL запрос за пределы цикла, убираем лимит 1, меняем SQLSelectOne на mysql_query и добавляем строку с mysql_fetch_array. Всё.

Субъективно скорость при работе с графиками возрасла раз в десять(!). И загрузка системы упала раз в десять(!), правда у меня много графиков.

Специалистам по php надо проверить это изменение и добавить проверку на ошибки.


Старый код

Код: Выделить всё


  while($start_time<$end_time) {

     $ph=SQLSelectOne("SELECT ID, VALUE FROM phistory WHERE VALUE_ID='".$pvalue['ID']."' AND ADDED<=('".date('Y-m-d H:i:s', $start_time)."') ORDER BY ADDED DESC LIMIT 1");

Новый код

Код: Выделить всё


   $ph6=mysql_query("SELECT ID, VALUE FROM phistory WHERE VALUE_ID='".$pvalue['ID']."' AND ADDED<=('".date('Y-m-d H:i:s', $start_time)."') ORDER BY ADDED DESC");

  while($start_time<$end_time) {

  $ph=mysql_fetch_array($ph6);

Кстати, а что это за функция такая SQLSelectOne, даже документации по ней не нашёл.

Re: Эффективность алгоритма

Добавлено: Сб дек 08, 2012 12:56 pm
sergejey
Погоди-ка... и оно так работает? Как-то странно ))
просто у тебя получается, что условия выборки задаётся один раз и по идее каждый раз должно одно и то же в цикле возвращаться. в общем, я сейчас ещё посмотрю. может сам туплю ))

Re: Эффективность алгоритма

Добавлено: Сб дек 08, 2012 1:09 pm
Alex
Погоди-ка... и оно так работает?
:D Это мне напомнило Ералаш "проверим делением" :D

Re: Эффективность алгоритма

Добавлено: Сб дек 08, 2012 1:17 pm
sergejey
Я кажется понял почему оно работает и где подводные камни... В общем, при идеальной и равномерной записи в таблицу данных оно будет работать, но вот если данные сохраняются неравномерно, то уже могут пойти сбои. Я переделал алгоритм в графиках сейчас и вроде стало пошустрее, т.к. одним запросом делается выборка и потом уже в цикле идёт подгонка соответствия точек.

Смотри что получилось.
Убираем:

Код: Выделить всё

   while($start_time<$end_time) {
     $ph=SQLSelectOne("SELECT ID, VALUE FROM phistory WHERE VALUE_ID='".$pvalue['ID']."' AND ADDED<=('".date('Y-m-d H:i:s', $start_time)."') ORDER BY ADDED DESC LIMIT 1");
     if ($ph['ID']) {
      $values[]=(float)$ph['VALUE'];
     } else {
      $values[]=0;
     }
     if ($px_passed>30) {
      if (date('Y-m-d', $start_time)!=$dt) {
       $hours[]=date('d/m', $start_time);
       $dt=date('Y-m-d', $start_time);
      } else {
       $hours[]=date('H:i', $start_time);
      }
      $px_passed=0;
     } else {
      $hours[]='';
     }
     $start_time+=$period;
     $px+=$px_per_point;
     $px_passed+=$px_per_point;
   }
Заменяем на:

Код: Выделить всё

   $history=SQLSelect("SELECT ID, VALUE, UNIX_TIMESTAMP(ADDED) as UNX FROM phistory WHERE VALUE_ID='".$pvalue['ID']."' AND ADDED>=('".date('Y-m-d H:i:s', $start_time)."') AND ADDED<=('".date('Y-m-d H:i:s', $end_time)."') ORDER BY ADDED");
   $total=count($history);
   $itm=0;
   for($i=0;$i<$total;$i++) {
    $unx=$history[$i]['UNX'];
    if ($unx>=$start_time || $i==0) {
     $values[$itm]=(float)$history[$i]['VALUE'];
     $itm++;
     $start_time+=$period;
     if ($px_passed>30) {
      if (date('Y-m-d', $unx)!=$dt) {
       $hours[]=date('d/m', $unx);
       $dt=date('Y-m-d', $unx);
      } else {
       $hours[]=date('H:i', $unx);
      }
      $px_passed=0;
     } else {
      $hours[]='';
     }
     $px+=$px_per_point;
     $px_passed+=$px_per_point;
    }
   }

Re: Эффективность алгоритма

Добавлено: Сб дек 08, 2012 2:40 pm
Alex
Вопрос теоретический, но хочется всё таки разобраться для себя.
В общем, при идеальной и равномерной записи в таблицу данных оно будет работать, но вот если данные сохраняются неравномерно, то уже могут пойти сбои.
Что понимается под неравномерной записью данных в таблицу? И почему должны пойти сбои? Что тут имеется в виду.?

Дело в том, что я не изменял сам алгоритм в цикле (предполагаем, что он правильный). А функция mysql_query по запросу просто выдаёт массив отсортированных точек со времени start до текущего времени. Как записывались данные в таблицу и как выдавать запрос — это дело (и проблемы) движка базы данных, мы просто получаем отсортированный массив, который обрабатываем в цикле. Откуда возьмутся сбои (если их до сих пор не было)?

Re: Эффективность алгоритма

Добавлено: Сб дек 08, 2012 3:49 pm
sergejey
Alex писал(а):Вопрос теоретический, но хочется всё таки разобраться для себя.
В общем, при идеальной и равномерной записи в таблицу данных оно будет работать, но вот если данные сохраняются неравномерно, то уже могут пойти сбои.
Что понимается под неравномерной записью данных в таблицу? И почему должны пойти сбои? Что тут имеется в виду.?

Дело в том, что я не изменял сам алгоритм в цикле (предполагаем, что он правильный). А функция mysql_query по запросу просто выдаёт массив отсортированных точек со времени start до текущего времени. Как записывались данные в таблицу и как выдавать запрос — это дело (и проблемы) движка базы данных, мы просто получаем отсортированный массив, который обрабатываем в цикле. Откуда возьмутся сбои (если их до сих пор не было)?
Имеющийся алгоритм разбивает промежуток времени на равные интервалы и берёт значение на начало каждого интервала. У тебя сделана выборка так, что значения должны быть так же равномерно сохранены в базе данных, в этом случае всё ок, но если, предположим, по каким-то причинам из 10 положенных за данный интервал значений в базе оказалось всего два (ну там не поступали данные по какой-то причине), то твой алгоритм выберет эти два единственных значения, независимо от того в какое время они происходили на всём интервале и разместит их в начале графика.

Re: Эффективность алгоритма

Добавлено: Сб дек 08, 2012 4:30 pm
Alex
если, предположим, по каким-то причинам из 10 положенных за данный интервал значений в базе оказалось всего два (ну там не поступали данные по какой-то причине), то твой алгоритм выберет эти два единственных значения, независимо от того в какое время они происходили на всём интервале и разместит их в начале графика.

Действительно, похоже это так. С этим моментом мне всё ясно.

На будущее. В некоторых случаях (например мониторинг качества сетевого напряжения) важно видеть всплески напряжения на графике. А наш алгоритм выбирает ближайшую точку к start time и, естественно, все пики пропускает. Мало того, раз от раза start time меняется и график, при обновлении, на том же участке меняет свой вид. Иногда кардинально, что не есть гут.

Бывает и обратная ситуация, когда сенсор выдаёт (по уважительной причине) редкие отклонения значения и график показывает всплески параметра, которых нет на самом деле. Тут нужен лёгкий усредняющий фильтр. Где нибудь в параметрах &mid=1.

А новый код сейчас попробую протестировать...