Способ повышения производительности следующего запроса (таблица обновлений) - PullRequest
0 голосов
/ 29 марта 2011

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

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

SensorID --- TimestampMS --- RawData --- Data

Так, например, для датчика температурыназывается TEMPSensor1 У меня есть следующее:

TEMPSensor1 --- 1000 --- 200 --- 2
TEMPSensor1 --- 2000 --- 220 --- 2.2

И так далее, для каждого датчика (всего у меня 8).У меня есть некоторые проблемы с чтением данных, и есть строки, данные которых "неверны".Точно, когда поле rawdata равно 65535, я должен обновить эту конкретную строку.И что я хотел бы сделать, это поставить следующее значение (по времени) для этих «поврежденных данных».Итак, если у нас есть это:

TEMPSensor1 --- 1000 --- 200 --- 2
TEMPSensor1 --- 2000 --- 220 --- 2.2
TEMPSensor1 -- 3000 --- 65535 --- 655.35
TEMPSensor1 --- 4000 --- 240 --- 2.4

После выполнения обновления содержимое таблицы должно быть изменено на:

TEMPSensor1 --- 1000 --- 200 --- 2
TEMPSensor1 --- 2000 --- 220 --- 2.2
TEMPSensor1 --- 3000 ---240 --- 2.4
TEMPSensor1 --- 4000 --- 240 --- 2.4

В итоге я сделал следующее:

UPDATE externalsensor es1
INNER JOIN externalsensor es2 ON es1.sensorid = es2.sensorid AND (es2.timestampms - es1.timestampms) > 60000 AND (es2.timestampms - es1.timestampms) < 120000  AND es1.rawdata <> 65535
SET es1.rawdata = es2.rawdata, es1.data = es2.data
WHERE es1.rawdata = 65535

Потому что яЗнайте, что между двумя считываниями с датчика существует от 60000 до 120000 мс.Однако, если у меня есть два следующих «испорченных» чтения, это не сработает.Может кто-нибудь предложить способ сделать это более эффективно, без использования выбора подзапроса, но JOINS?Моя идея состояла бы в том, чтобы иметь JOIN, который дает вам все возможные значения для этого датчика после его временных меток, и просто получить первое, но я не знаю, как я могу ограничить этот результат JOIN.

Оценить.

Ответы [ 3 ]

2 голосов
/ 30 марта 2011

Вот решение без коррелированных подзапросов, но с треугольным соединением (не уверен, что хуже):

UPDATE externalsensor bad

  INNER JOIN (
    SELECT
      es1.SensorID,
      es1.TimestampMS,
      MIN(es2.TimestampMS) AS NextGoodTimestamp
    FROM externalsensor es1
      INNER JOIN externalsensor es2
        ON es1.SensorID = es2.SensorID AND
           es1.TimestampMS < es2.TimestampMS
    WHERE es1.RawData = 65535
      AND es2.RawData <> 65535
    GROUP BY
      es1.SensorID,
      es1.TimestampMS
  ) link ON bad.SensorID = link.SensorID AND
            bad.TimestampMS = link.TimestampMS

  INNER JOIN externalsensor good
    ON link.SensorID = good.SensorID AND
       link.NextGoodTimestamp = good.TimestampMS

SET
  bad.RawData = good.RawData,
  bad.Data = good.Data

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

1 голос
/ 31 марта 2011

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

DELIMITER $$
CREATE PROCEDURE updateMyTable()
BEGIN
  SET @dummy := -9999 ;
  SET @dummy2 := -9999 ;
  SET @sensor := -999 ;

  UPDATE myTable m
    JOIN 
    ( SELECT n.SensorID
           , n.TimestampMS
           , @d := (n.RawData = 65535) AND (@sensor = n.SensorID) AS problem
           , @dummy  := IF(@d, @dummy, n.RawData) as goodRawData
           , @dummy2 := IF(@d, @dummy2, n.Data) as goodData
           , @sensor := n.SensorID AS previous
      FROM myTable n
      ORDER BY n.SensorID
             , n.TimeStampMS DESC
    ) AS upd
    ON m.SensorID = upd.SensorID
      AND m.TimeStampMS = upd.TimeStampMS
  SET m.RawData = upd.goodRawData
    , m.Data = upd.goodData
  WHERE upd.problem
  ;
END$$
DELIMITER ;
1 голос
/ 29 марта 2011

Поскольку вы не хотите использовать решение Dems из предыдущего вопроса, вот «решение» с JOIN:

UPDATE myTable m
  JOIN myTable n
    ON m.SensorID = n.SensorID
      AND n.RawData <> 65535
      AND m.TimestampMS < n.TimestampMS
  JOIN myTable q
    ON n.SensorID = q.SensorID
      AND q.RawData <> 65535
      AND n.TimestampMS <= q.TimestampMS
SET
  m.RawData = n.RawData,
  m.Data = n.Data
WHERE
   m.RawData = 65535
;

EDIT

Мой запрос выше неправильный, совершенно неверный. Кажется, он работает в моем тестовом БД, но логика ошибочна. Я объясню ниже.

Почему вышеупомянутый запрос работает нормально, но совершенно неверно:

Во-первых, почему это не так.

Потому что он не будет возвращать одну строку для каждой комбинации (sensorID, неверная метка времени), но много строк. Если m (m.TimestampMS) - это неправильная временная метка, которую мы хотим найти, она вернет все комбинации этой неправильной временной метки и более поздних хороших временных меток n и q с n.TimestampMS <= q.TimestampMS. Это был бы правильный запрос, если бы он нашел МИНИМУМ этих n отметок времени.

Теперь, как же это на самом деле работает нормально в моем тестовом БД?

Я думаю, это потому, что MySQL, когда он использует SET ... и имеет много опций (строк), просто использует первый вариант. Но, к счастью, я добавил тестовые строки в порядке возрастания меток времени, чтобы они были сохранены в том же порядке в БД, и (опять же, к счастью для меня, именно так запланирован план запроса (я полагаю).

Даже этот запрос работает в моей тестовой базе данных:

UPDATE myTable m
  JOIN myTable n
    ON m.SensorID = n.SensorID
      AND n.RawData <> 65535
      AND m.TimestampMS < n.TimestampMS
SET
  m.RawData = n.RawData,
  m.Data = n.Data
WHERE
   m.RawData = 65535
;

будучи ошибочным по тем же причинам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...