2013-05-08 2 views
0

У меня есть база данных измерений, которые показывают датчик, показание и отметку времени, в которой были сделаны данные. Измерения записываются только в случае изменения. Я хочу создать набор результатов, который показывает диапазон, в котором каждый датчик считывает определенное измерение.MySQL - перетаскивание точек данных в диапазоны

Временные метки в миллисекундах, но я выводя результат в секундах.

Вот таблица:

CREATE TABLE `raw_metric` (
    `row_id` BIGINT NOT NULL AUTO_INCREMENT, 
    `sensor_id` BINARY(6) NOT NULL, 
    `timestamp` BIGINT NOT NULL, 
    `angle` FLOAT NOT NULL, 
    PRIMARY KEY (`row_id`) 
) 

Сейчас я получаю результаты, я хочу с помощью подзапроса, но это довольно медленно, когда есть много точек данных:

SELECT row_id, 
    HEX(sensor_id), 
    angle, 
    (
     COALESCE((
       SELECT MIN(`timestamp`) 
       FROM raw_metric AS rm2 
       WHERE rm2.`timestamp` > rm1.`timestamp` 
        AND rm2.sensor_id = rm1.sensor_id 
       ), UNIX_TIMESTAMP() * 1000) - `timestamp` 
     )/1000 AS duration 
FROM raw_metric AS rm1 

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

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

UPDATE: row_id-х должен увеличиваться вместе с временными метками, но она не может быть гарантирована из-за задержек в сети. Таким образом, возможно, что запись с более низким значением row_id появляется ПОСЛЕ более позднего row_id, хотя и маловероятна.

+0

Правильный способ улучшить производительность этого подзапроса - это указать индекс на 'raw_metric (sensor_id, timestamp)'. Я бы предложил добавить индекс и проверить производительность вставок. –

+0

@GordonLinoff Да, это был бы лучший способ улучшить подзапрос, но есть ли другой (надеюсь, лучший) способ сделать это _without_ подзапроса? –

+0

@GordonLinoff Как создать временную таблицу raw_metric с индексированными временными метками? –

ответ

0

Если вы используете auto_increment для первичного ключа, вы можете заменить timestamp на row_id в части условия запроса. Например:

SELECT row_id, 
HEX(sensor_id), 
angle, 
(
    COALESCE((
      SELECT MIN(`timestamp`) 
      FROM raw_metric AS rm2 
      WHERE rm2.`row_id` > rm1.`row_id` 
       AND rm2.sensor_id = rm1.sensor_id 
      ), UNIX_TIMESTAMP() * 1000) - `timestamp` 
    )/1000 AS duration 
FROM raw_metric AS rm1 

Должно работать быстро.

Также вы можете добавить еще один подзапрос для быстрого выбора идентификатора строки нового значения датчика. См:

SELECT row_id, 
HEX(sensor_id), 
angle, 
(
    COALESCE((
     SELECT timestamp FROM raw_metric AS rm1a 
     WHERE row_id = 
     (
      SELECT MIN(`row_id`) 
      FROM raw_metric AS rm2 
      WHERE rm2.`row_id` > rm1.`row_id` 
       AND rm2.sensor_id = rm1.sensor_id 
     ) 
     ), UNIX_TIMESTAMP() * 1000) - `timestamp` 
    )/1000 AS duration 
FROM raw_metric AS rm1 
+0

добавил обновление ... Я не могу гарантировать, что row_id будут следовать этому пути. –

0
Select rm1.row_id 
     ,HEX(rm1.sensor_id) 
     ,rm1.angle 
     ,(COALESCE(rm2.timestamp, UNIX_TIMESTAMP() * 1000) - rm1.timestamp) as duration 
from raw_metric rm1 
left outer join 
     raw_metric rm2 
on  rm2.sensor_id = rm1.sensor_id 
and  rm2.timestamp = (
      select min(timestamp) 
      from raw_metric rm3 
      where rm3.sensor_id = rm1.sensor_id 
      and rm3.timestamp > rm1.timestamp 
      ) 
+0

Я не уверен, что понимаю, как это улучшение. Разве это не все тот же подзапрос, но теперь он добавляет соединение? –

1

Это, пожалуй, более уместно в качестве комментария, чем в качестве решения, но это слишком долго для комментария.

Вы пытаетесь реализовать функцию lead() в MySQL, а MySQL, к сожалению, не имеет оконных функций. Вы можете переключиться на Oracle, DB2, Postgres, SQL Server 2012 и использовать встроенные (и оптимизированные) функции там. Хорошо, это может быть нереалистично.

Таким образом, учитывая вашу структуру данных, вам необходимо выполнить либо коррелированный подзапрос, либо не равноденствие (на самом деле это частичное equi-join, потому что есть совпадение на sensor_id). Это будут дорогостоящие операции, если вы не добавите индекс. Если вы не добавляете измерения десятки раз в секунду, дополнительные накладные расходы по индексу не должны иметь большого значения.

Вы также можете изменить структуру данных. Если у вас был «счетчик датчиков», который был последовательным номером, перечисляющим показания, то вы могли бы использовать его как эквити (хотя для хорошей производительности вам может понадобиться индекс). Добавление этого в вашу таблицу потребует наличия триггера - и это, вероятно, будет хуже, чем индекс при вставке.

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

В конце концов, я могу предположить, что вы принимаете удар во время вставки и имеете «эффективные» и «конечные» времена на каждой записи (а также индекс на идентификаторе датчика, а также временную метку или идентификатор). столбцы, вы, вероятно, найдете больше применений для таблицы.

Если вы делаете это только для одного датчика, создайте временную таблицу для информации и используйте столбец с автоинкрементным идентификатором, а затем вставьте в него данные:

insert into temp_rawmetric (orig_row_id, sensor_id, timestamp, angle) 
    select orig_row_id, sensor_id, timestamp, angle 
    from raw_metric 
    order by sensor_id, timestamp; 

Убедитесь, что ваша таблица имеет temp_rawmetric_id столбец, который автоматически увеличивается и первичный ключ (создает IND ex автоматически). order by гарантирует, что это увеличивается в соответствии с меткой времени.

Затем вы можете сделать запрос как:

select trm.sensor_id, trm.angle, 
     trm.timestamp as startTime, trmnext.timestamp as endTime 
from temp_rawmetric trm left outer join 
    temp_rawmetric trmnext 
    on trmnext.temp_rawmetric_id = trm.temp_rawmetric_id+1; 

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

+0

Я следил за вами до последнего абзаца ... Каковы эти дополнительные столбцы? –

+0

Я предполагаю, что «trmnext» должен был быть «trm2» в вашем последнем примере кода. Я все еще смущен вашим абзацем, говорящим: «Возьмите удар во время вставки и получите« эффективные »и« конечные »времена для каждой записи ... С помощью этих дополнительных столбцов вы, вероятно, найдете больше применений для таблицы». Вы говорите о каком-то дополнительном столбце таблицы, в который я вставляю значения при вставке в 'raw_metric'? –

Смежные вопросы