Эмуляция полного объединения в MYSQL с большим набором данных - PullRequest
1 голос
/ 29 ноября 2011

У меня есть три таблицы, данные которых мне нужно объединить на основе общего поля.

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

barometer_log (устройство, поплавок,временная метка sampleTime)

Журнал температурного режима (int устройства, всплеск температуры, временная метка sampleTime)

magnitude_log (int устройства, поплавок магнитуды, временная метка utcTime)

Каждая из таблиц в конечном итоге будет содержать миллиарды строк, но в настоящее время каждая содержит около 500 000 строк.

Мне нужно объединить данные (FULL JOIN) из таблиц так, чтобы sampleTime объединен в один столбец (COALESE), чтобы дать мне строки: device, sampleTime, давление, температура, величина

Мне нужно иметь возможность запрашивать данные, указавустройство, дата начала и окончания, например, выберите ...., где устройство = 1000 и sampleTime между '2011-10-11' и '2011-10-17'

Я пробовал разныеUNION ALL техника с правым и левым соединением, как предложенов MySql полное объединение (объединение) и упорядочение по нескольким столбцам даты и MySql полное объединение (объединение) и упорядочение по нескольким столбцам даты , но запрос занимает слишком много времени, и я должен остановитьсяон или выдает ошибку о размере временного файла после нескольких часов работы.Каков наилучший способ для меня запросить три таблицы и объединить их вывод в приемлемый период времени?

Вот полное определение таблицы, как предлагается.примечание: таблица устройств не была включена

Ответы [ 3 ]

1 голос
/ 29 ноября 2011

Сначала получите все комбинации (device, sampleTime) из всех 3 таблиц за требуемый период:

-------- Q --------
    SELECT device, sampleTime
    FROM magnitude_log
    WHERE device = 1000
      AND sampleTime >= '2011-10-11' 
      AND sampleTime <  '2011-10-18'
UNION
    SELECT device, sampleTime
    FROM barometer_log
    WHERE device = 1000
      AND sampleTime >= '2011-10-11' 
      AND sampleTime <  '2011-10-18'
UNION
    SELECT device, sampleTime
    FROM temperature_log
    WHERE device = 1000
      AND sampleTime >= '2011-10-11' 
      AND sampleTime <  '2011-10-18'

Затем используйте это для LEFT JOIN 3 таблиц:

SELECT
    q.device
  , q.sampleTime
  , b.pressure
  , t.temperature
  , m.magnitude
FROM 
    ( Q ) AS q
  LEFT JOIN
    ( SELECT * 
      FROM magnitude_log 
      WHERE device = 1000
        AND sampleTime >= '2011-10-11' 
        AND sampleTime <  '2011-10-18'
    ) AS m
      ON (m.device, m.sampleTime) = (q.device, q.sampleTime)
  LEFT JOIN
    ( SELECT * 
      FROM barometer_log 
      WHERE device = 1000
        AND sampleTime >= '2011-10-11' 
        AND sampleTime <  '2011-10-18'
    ) AS b
      ON (b.device, b.sampleTime) = (q.device, q.sampleTime)
  LEFT JOIN
    ( SELECT * 
      FROM temperature_log_log 
      WHERE device = 1000
        AND sampleTime >= '2011-10-11' 
        AND sampleTime <  '2011-10-18'
    ) AS t
      ON (t.device, t.sampleTime) = (q.device, q.sampleTime)

Чем дольше период, тем дольше запрос будет бороться с подзапросом UNION. Вы можете подумать о том, чтобы поместить Q в отдельную таблицу, возможно, заполнив ее триггерами уникальными комбинациями (device, sampleTime) из трех других таблиц.

0 голосов
/ 29 ноября 2011

Если вы запрашиваете небольшой диапазон времени и большое количество устройств, вы можете рассмотреть возможность обращения к индексу PK, чтобы сделать это (timeRange, device).

Возможно, вам понадобится вторичный индекс на устройстве или (device, timeRange).

0 голосов
/ 29 ноября 2011

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

SELECT
    d.id AS device,
    COALESCE(m.sampleTime, b.sampleTime, t.sampleTime) AS sampleTime,
    m.magnitude,
    b.pressure,
    t.temperature
FROM device AS d
    LEFT JOIN magnitude_log AS m ON d.id = m.device
    LEFT JOIN barometer_log AS b ON d.id = b.device
    LEFT JOIN temperature_log AS t ON d.id = t.device
WHERE d.id = 1000
GROUP BY device, sampleTime
HAVING sampleTime BETWEEN '2011-10-11' AND '2011-10-17'

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

SELECT
    d.id AS device,
    COALESCE(m.sampleTime, b.sampleTime, t.sampleTime) AS sampleTime,
    m.magnitude,
    b.pressure,
    t.temperature
FROM device AS d
    LEFT JOIN magnitude_log AS m ON d.id = m.device AND m.sampleTime BETWEEN '2011-10-11' AND '2011-10-17'
    LEFT JOIN barometer_log AS b ON d.id = b.device AND b.sampleTime BETWEEN '2011-10-11' AND '2011-10-17'
    LEFT JOIN temperature_log AS t ON d.id = t.device AND t.sampleTime BETWEEN '2011-10-11' AND '2011-10-17'
WHERE d.id = 1000
GROUP BY device, sampleTime
HAVING sampleTime IS NOT NULL

Надеюсь, это поможет!

...