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

Использование системы в различных ситуациях, вопросы программирования сценариев.

Модератор: immortal

Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

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

Сообщение Alex » Пт дек 07, 2012 6:16 pm

Посмотрел я тут код и у меня возник вопрос. Выходит, что для получения каждой точки он (алгоритм) посылает отдельный 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");
  }
Аватара пользователя
sergejey
Site Admin
Сообщения: 4286
Зарегистрирован: Пн сен 05, 2011 6:48 pm
Откуда: Минск, Беларусь
Благодарил (а): 76 раз
Поблагодарили: 1559 раз
Контактная информация:

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

Сообщение sergejey » Пт дек 07, 2012 6:52 pm

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

Сергей Джейгало, разработчик MajorDoMo
Идеи, ошибки -- за предложениями по исправлению и развитию слежу только здесь!
Профиль Connect -- информация, сотрудничество, услуги
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

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

Сообщение Alex » Пт дек 07, 2012 7:10 pm

То ли я графики очень люблю, :) то ли чего, но у меня система уже встала. Нажимаем на страничку и 20 секунд ждём отрисовки паршивенького графика. Я конечно попробую переписать этот кусок, но не уверен, что моих познаний будет достаточно. Ау, php программисты! Мы ищем таланты!
:D
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

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

Сообщение Alex » Сб дек 08, 2012 12:02 pm

Итак,

выносим 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, даже документации по ней не нашёл.
Аватара пользователя
sergejey
Site Admin
Сообщения: 4286
Зарегистрирован: Пн сен 05, 2011 6:48 pm
Откуда: Минск, Беларусь
Благодарил (а): 76 раз
Поблагодарили: 1559 раз
Контактная информация:

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

Сообщение sergejey » Сб дек 08, 2012 12:56 pm

Погоди-ка... и оно так работает? Как-то странно ))
просто у тебя получается, что условия выборки задаётся один раз и по идее каждый раз должно одно и то же в цикле возвращаться. в общем, я сейчас ещё посмотрю. может сам туплю ))

Сергей Джейгало, разработчик MajorDoMo
Идеи, ошибки -- за предложениями по исправлению и развитию слежу только здесь!
Профиль Connect -- информация, сотрудничество, услуги
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

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

Сообщение Alex » Сб дек 08, 2012 1:09 pm

Погоди-ка... и оно так работает?
:D Это мне напомнило Ералаш "проверим делением" :D
Аватара пользователя
sergejey
Site Admin
Сообщения: 4286
Зарегистрирован: Пн сен 05, 2011 6:48 pm
Откуда: Минск, Беларусь
Благодарил (а): 76 раз
Поблагодарили: 1559 раз
Контактная информация:

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

Сообщение sergejey » Сб дек 08, 2012 1:17 pm

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

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

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

   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;
    }
   }

Сергей Джейгало, разработчик MajorDoMo
Идеи, ошибки -- за предложениями по исправлению и развитию слежу только здесь!
Профиль Connect -- информация, сотрудничество, услуги
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

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

Сообщение Alex » Сб дек 08, 2012 2:40 pm

Вопрос теоретический, но хочется всё таки разобраться для себя.
В общем, при идеальной и равномерной записи в таблицу данных оно будет работать, но вот если данные сохраняются неравномерно, то уже могут пойти сбои.
Что понимается под неравномерной записью данных в таблицу? И почему должны пойти сбои? Что тут имеется в виду.?

Дело в том, что я не изменял сам алгоритм в цикле (предполагаем, что он правильный). А функция mysql_query по запросу просто выдаёт массив отсортированных точек со времени start до текущего времени. Как записывались данные в таблицу и как выдавать запрос — это дело (и проблемы) движка базы данных, мы просто получаем отсортированный массив, который обрабатываем в цикле. Откуда возьмутся сбои (если их до сих пор не было)?
Аватара пользователя
sergejey
Site Admin
Сообщения: 4286
Зарегистрирован: Пн сен 05, 2011 6:48 pm
Откуда: Минск, Беларусь
Благодарил (а): 76 раз
Поблагодарили: 1559 раз
Контактная информация:

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

Сообщение sergejey » Сб дек 08, 2012 3:49 pm

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

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

Сергей Джейгало, разработчик MajorDoMo
Идеи, ошибки -- за предложениями по исправлению и развитию слежу только здесь!
Профиль Connect -- информация, сотрудничество, услуги
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

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

Сообщение Alex » Сб дек 08, 2012 4:30 pm

если, предположим, по каким-то причинам из 10 положенных за данный интервал значений в базе оказалось всего два (ну там не поступали данные по какой-то причине), то твой алгоритм выберет эти два единственных значения, независимо от того в какое время они происходили на всём интервале и разместит их в начале графика.

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

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

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

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