mysql db для значений времени и температуры

Мне нужна ваша помощь, чтобы правильно построить мою БД.

Мне нужно хранить значения температуры и времени для разных комнат моего дома, и я хочу использовать DyGraph для построения графиков наборов данных. Я хочу реализовать разные временные окна: 1 час, 24 часа, 48 часов, 1 неделя, ....

Я буду определять температуру с 15-минутным интервалом, поэтому у меня будет 4 значения времени-температуры в час. Каждая комната имеет идентификатор, поэтому значения времени и температуры будут связаны с соответствующей комнатой.

Таблица, которую я построил, очень проста:

----------------------------------
| ID |      DATE          | TEMP |
----------------------------------
| 1  |2014-04-30 00:00:00 | 18.6 |
----------------------------------
| 2  |2014-04-30 00:00:00 | 18.3 |
----------------------------------
| 3  |2014-04-30 00:00:00 | 18.3 |
----------------------------------
| 1  |2014-04-30 00:15:00 | 18.5 |
----------------------------------

По какой-то странной причине, когда количество строк достигает 500 или около того, сервер становится очень медленным. Кроме того, у меня есть веб-страница, на которой я могу читать разные температуры в комнатах: эта страница опрашивает сервер через AJAX каждые 5 секунд (потому что ее нужно часто обновлять!), но когда количество строк таблицы становится около 500, он зависает.

Я попытался разделить таблицу и создал таблицу для каждой комнаты, затем таблицу для каждого временного окна, и теперь все работает нормально.

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

Я использую php-скрипт для получения данных о температуре во всех комнатах моего дома:

$query = "SELECT * FROM temperature t1 
          WHERE (id, date) IN 
          (SELECT id,MAX(date) FROM
          temperature t2 GROUP BY id)";

этот запрос позволяет мне собирать значения температуры в массив с именем $options:

$result_set = mysql_query($query, $connection);             
while($rows = mysql_fetch_array($result_set)){
$options [] = $rows;
}

затем я json-кодирую массив:

$j = json_encode($options);

и отправить его в ajax-скрипт, который показывает данные на веб-странице:

echo $j;

В сценарии ajax я сохраняю данные в переменной, а затем анализирую их:

var return_data = xhr.responseText;
var temperature = JSON.parse(return_data);

затем я перебираю массив, чтобы извлечь значения температуры и поместить их в нужное место на веб-странице:

for(var j=0; j<temperature.length; j++){
  document.getElementById("TEMPArea" + j).innerHTML = temperature[j].temp + "&deg;C";
}

Это работает нормально, пока количество строк в таблице 'temperature' меньше 600 или около того: опрос каждые 5 секунд не является проблемой. Выше 600 обновление страницы становится медленным и в конечном итоге зависает и перестает обновляться.

РЕДАКТИРОВАТЬ: Сейчас я работаю над виртуальной машиной с 64-битной Windows 7, Apache, PHP и MySQL, 4 ГБ ОЗУ. Как вы думаете, это может быть проблемой?


person Tercol    schedule 30.04.2014    source источник
comment
Априори нет ничего плохого в структуре, подобной той, которую вы показываете, в мире баз данных таблица с 500 строками считается смехотворно маленькой, и тот факт, что ваша система становится чрезвычайно медленной, вплоть до полного зависания, указывает на то, что есть что-то очень очень неправильный. Можете ли вы опубликовать код и схему базы данных? Разделение таблиц, как вы пытались, просто скроет эти проблемы на какое-то время, но приведет к огромным структурным проблемам, которые заразят весь ваш код.   -  person fvu    schedule 30.04.2014
comment
Просто чтобы дать вам представление: я смотрю здесь на систему, которая в основном является несколько увеличенной версией того, что вы хотите, с таблицей измеренных значений, содержащей 23 миллиона строк сотен точек измерения. Извлечение последнего значения для некоторого случайного датчика занимает около 11 миллисекунд, получение последних 1000 значений для некоторого случайного датчика около 33 миллисекунд...   -  person fvu    schedule 30.04.2014
comment
вы приносите 500 строк в браузер? вы используете пейджинг?   -  person Martín Schonaker    schedule 30.04.2014
comment
@Tercol, хотя это потенциально может быть интересным вопросом, полное отсутствие технических подробностей о том, что вы уже пробовали, подвергает его риску закрытия как слишком широкого или неясного, поэтому, пожалуйста, добавьте некоторый код и детали базы данных.   -  person fvu    schedule 30.04.2014
comment
@fvu, добавить особо нечего: я такой новичок в этом ... Моя проблема в том, что по мере роста объема данных, которые мне нужны, я начинаю получать ошибку «Максимальное время выполнения xx секунд превышено». Я знаю, что могу изменить значение времени выполнения в php.ini (что я и сделал), но я думал, что это как-то связано со структурой базы данных. Я использую php для получения значений.   -  person Tercol    schedule 01.05.2014
comment
@mschonaker, нет, я не вывожу в браузер 500 строк. Мне нужно только 6 значений, которые являются последними из каждой комнаты. Кроме того, температура — это не единственное, что мне нужно проверить, поэтому я делаю несколько запросов подряд каждые 5 секунд.   -  person Tercol    schedule 01.05.2014
comment
@Tercol, как я объяснял ранее, нагрузка на БД для выполнения описанной вами задачи не должна быть даже заметной. Следовательно, ключ к проблеме можно найти в вашем коде, но вы, похоже, не хотите его показывать. Это ваш выбор, но это также означает, что кроме переписывания полного решения от а до я для вас на основе предоставленных вами мелких деталей здесь нет ничего полезного, и поэтому я голосую за закрытие этот вопрос как отсутствие достаточной информации для диагностики проблемы.   -  person fvu    schedule 01.05.2014
comment
Уточнения @Tercol следует вводить в вопрос, а не как ответ. Я переместил их для вас. Следующий вопрос: есть ли у вас какие-либо индексы в вашей таблице?   -  person fvu    schedule 05.05.2014


Ответы (2)


Кажется, я был беден в деталях, так что вот еще кое-что к тому, что я сказал.

Я использую php-скрипт для получения данных о температуре во всех комнатах моего дома:

$query = "SELECT * FROM temperature t1 
          WHERE (id, date) IN 
          (SELECT id,MAX(date) FROM
          temperature t2 GROUP BY id)";

этот запрос позволяет мне собирать значения температуры в массив с именем $options:

$result_set = mysql_query($query, $connection);             
while($rows = mysql_fetch_array($result_set)){
$options [] = $rows;
}

затем я json-кодирую массив:

$j = json_encode($options);

и отправить его в ajax-скрипт, который показывает данные на веб-странице:

echo $j;

В сценарии ajax я сохраняю данные в переменной, а затем анализирую их:

var return_data = xhr.responseText;
var temperature = JSON.parse(return_data);

затем я перебираю массив, чтобы извлечь значения температуры и поместить их в нужное место на веб-странице:

for(var j=0; j<temperature.length; j++){
  document.getElementById("TEMPArea" + j).innerHTML = temperature[j].temp + "&deg;C";
}

Как я сказал в первом сообщении, это работает нормально, пока количество строк в таблице 'temperature' меньше 600 или около того: опрос каждые 5 секунд не проблема. Выше 600 обновление страницы становится медленным и в конечном итоге зависает и перестает обновляться.

Я не эксперт, код довольно простой и понятный, поэтому у меня проблемы с определением причины. Спасибо еще раз.

person Tercol    schedule 02.05.2014

Я думаю, что запрос является основным источником проблем:

  • это медленный способ получения нужного вам ответа (вы всегда можете запустить его в Workbench и изучить вывод EXPLAIN — см. руководство для более подробной информации
  • он неявно предполагает, что все датчики передают одновременно, и как только это не так, ваш выходной набор данных не будет полным. Обычно вам нужны последние данные от каждого отдельного датчика.

поэтому я предлагаю несколько иной подход:

  1. добавьте индекс по дате и один по идентификатору, чтобы ускорить запросы. Отсутствие ПК — это проблема, но давайте сначала сосредоточимся на решении текущих проблем...
  2. получить список доступных датчиков - минимальное решение

    select distinct id from temperature;
    

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

  3. перебрать результаты этого списка, чтобы получить последнее значение для каждого из датчиков

    select * from temperature 
    where id = (value obtained in previous step) 
    order by date desc 
    limit 1;
    

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

  4. соберите эти результаты в структуру данных для отправки на веб-страницу вашего клиента.

Кроме того, как указано в документации, расширение mysql_* устарел и не должен использоваться в новых программах. Используйте mysqli_ или предпочтительно PDO. Оба этих расширения также позволяют использовать параметризованные запросы, единственную настоящую защиту от SQL. Проблемы с инъекцией. См. здесь краткое описание того, как их использовать.

person fvu    schedule 05.05.2014
comment
Вот это да! Это выглядит как продвинутый материал для меня! Я так новичок в этом, мне придется некоторое время «изучать» ваш ответ, чтобы понять его! Есть одна вещь (среди прочего), которая не ясна: как цикл по списку идентификаторов может быть быстрее, чем один запрос? Спасибо. - person Tercol; 05.05.2014
comment
@Tercol не торопитесь и не стесняйтесь обращаться за разъяснениями. Несколько упрощая, причина в том, что некоторые запросы заставляют db-сервер выполнять очень сложную или итеративную работу (например, путем сравнения всех комбинаций элементов 2-х списков, страшное декартово произведение), а последовательность более или менее эквивалентных простых запросов позволяет сервер - например, с помощью индексов - чтобы получить результат намного быстрее без большого количества поисков и обработки. - person fvu; 06.05.2014