1

共通のフィールドに基づいてデータを結合する必要がある 3 つのテーブルがあります。

サンプル疑似テーブル定義:

barometer_log (デバイス、圧力フロート、sampleTime タイムスタンプ)

temperature_log (デバイス整数、温度フロート、sampleTime タイムスタンプ)

Magnitude_log (デバイス int、マグニチュードfloat、utcTime タイムスタンプ)

各テーブルには最終的に数十億行が含まれますが、現在はそれぞれ約 500,000 行が含まれています。

テーブルからのデータ (FULL JOIN) を結合して、sampleTimeが 1 つの列 (COALESE) としてマージされ 、デバイス、サンプル時間、圧力、温度、マグニチュードとして行が得られるようにする必要があります。

デバイスと開始日と終了日を指定してデータをクエリできるようにする必要があります

MySql full join (union) and order on multiple date columnsおよびMySql full join (union) and order on multiple date columnsで提案されているように、RIGHT 結合と LEFT 結合を使用して別の UNION ALL 手法を試しましたが、クエリに時間がかかりすぎて、停止するか、何時間も実行した後に一時ファイルのサイズに関するエラーをスローします。3 つのテーブルにクエリを実行し、許容できる時間枠内でそれらの出力をマージするにはどうすればよいですか?

提案されている完全なテーブル定義を次に示します。注: デバイス テーブルは含まれていません。

マグニチュード_ログ

CREATE TABLE magnitude_log (
  device int(11) NOT NULL,
  magnitude float not NULL,
  sampleTime timestamp NOT NULL,  
  PRIMARY KEY  (device,sampleTime),
  CONSTRAINT magnitudeLog_device 
    FOREIGN KEY (device) 
      REFERENCES device (id) 
      ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

barometer_log

CREATE TABLE barometer_log (
  device int(11) NOT NULL,
  pressure float not NULL,  
  sampleTime timestamp NOT NULL,  
  PRIMARY KEY  (device,sampleTime),
  CONSTRAINT barometerLog_device 
    FOREIGN KEY (device) 
      REFERENCES device (id) 
      ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

温度_ログ

CREATE TABLE temperature_log (
  device int(11) NOT NULL,
  sampleTime timestamp NOT NULL,  
  temperature float default NULL,
  PRIMARY KEY  (device,sampleTime),
  CONSTRAINT temperatureLog_device 
    FOREIGN KEY (device) 
      REFERENCES device (id) 
      ON DELETE CASCADE
)  ENGINE=InnoDB DEFAULT CHARSET=utf8;
4

3 に答える 3

1

まず、(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 JOIN3 つのテーブルに使用します。

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)、他の 3 つのテーブルからの一意の組み合わせで埋めます。

于 2011-11-29T07:21:24.593 に答える
0

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

それが役立つことを願っています!

于 2011-11-29T07:26:04.680 に答える
0

短い時間範囲と多数のデバイスを照会している場合は、PK インデックスを逆にして (timeRange,device) にすることを検討することをお勧めします。

おそらく、デバイスまたは (device,timeRange) にセカンダリ インデックスが必要です。

于 2011-11-29T08:22:05.147 に答える