コストのかかる部分は、相関サブクエリが各temperature_*
テーブルのすべての行の時間差を計算して、メイン クエリの 1 つの行の 1つの列に対して最も近い行を1 つだけ見つける必要があるところです。
インデックスに従って現在時刻の1行後と1行前を選択し、これら 2 つの候補の時間差のみを計算できれば、劇的に高速になります。それを高速にするために必要なのは、テーブルの列のインデックスだけです。time
zone
質問ではその役割が不明のままであり、コアの問題にノイズを追加するだけなので、列を無視しています。クエリに簡単に追加できるはずです。
追加のビューがない場合、このクエリはすべてを一度に実行します。
SELECT time
,COALESCE(temp1
,CASE WHEN timediff(time, time1a) > timediff(time1b, time) THEN
(SELECT t.temperature
FROM temperature_1 t
WHERE t.time = y.time1b)
ELSE
(SELECT t.temperature
FROM temperature_1 t
WHERE t.time = y.time1a)
END) AS temp1
,COALESCE(temp2
,CASE WHEN timediff(time, time2a) > timediff(time2b, time) THEN
(SELECT t.temperature
FROM temperature_2 t
WHERE t.time = y.time2b)
ELSE
(SELECT t.temperature
FROM temperature_2 t
WHERE t.time = y.time2a)
END) AS temp2
,COALESCE(temp3
,CASE WHEN timediff(time, time3a) > timediff(time3b, time) THEN
(SELECT t.temperature
FROM temperature_3 t
WHERE t.time = y.time3b)
ELSE
(SELECT t.temperature
FROM temperature_3 t
WHERE t.time = y.time3a)
END) AS temp3
FROM (
SELECT time
,max(t1) AS temp1
,max(t2) AS temp2
,max(t3) AS temp3
,CASE WHEN max(t1) IS NULL THEN
(SELECT t.time FROM temperature_1 t
WHERE t.time < x.time
ORDER BY t.time DESC LIMIT 1) ELSE NULL END AS time1a
,CASE WHEN max(t1) IS NULL THEN
(SELECT t.time FROM temperature_1 t
WHERE t.time > x.time
ORDER BY t.time LIMIT 1) ELSE NULL END AS time1b
,CASE WHEN max(t2) IS NULL THEN
(SELECT t.time FROM temperature_2 t
WHERE t.time < x.time
ORDER BY t.time DESC LIMIT 1) ELSE NULL END AS time2a
,CASE WHEN max(t2) IS NULL THEN
(SELECT t.time FROM temperature_2 t
WHERE t.time > x.time
ORDER BY t.time LIMIT 1) ELSE NULL END AS time2b
,CASE WHEN max(t3) IS NULL THEN
(SELECT t.time FROM temperature_3 t
WHERE t.time < x.time
ORDER BY t.time DESC LIMIT 1) ELSE NULL END AS time3a
,CASE WHEN max(t3) IS NULL THEN
(SELECT t.time FROM temperature_3 t
WHERE t.time > x.time
ORDER BY t.time LIMIT 1) ELSE NULL END AS time3b
FROM (
SELECT time, temperature AS t1, NULL AS t2, NULL AS t3 FROM temperature_1
UNION ALL
SELECT time, NULL AS t1, temperature AS t2, NULL AS t3 FROM temperature_2
UNION ALL
SELECT time, NULL AS t1, NULL AS t2, temperature AS t3 FROM temperature_3
) AS x
GROUP BY time
) y
ORDER BY time;
->sqlfiddle
説明
suqquery xはビューを置き換えtemptimes
、結果に温度をもたらします。3 つのテーブルすべてが同期しており、すべて同じ時点の温度がある場合、残りは必要なく、非常に高速です。
3 つのテーブルのうちの 1 つに行がないすべての時点で、指示に従って温度が取得されます。各テーブルから「最も近い」ものを取得します。
suqquery yは、温度が欠落している各テーブルからの行を集約し、現在の時間に従ってx
前回 ( time1a
) と次回( ) を取得します。time1b
これらのルックアップは、インデックスを使用して高速にする必要があります。
最後のクエリは、実際には欠落している各気温の最も近い時刻の行から気温を取得します。
MySQL が現在のサブクエリよりも 2 つ以上上のレベルから列を参照できるようになれば、このクエリはより単純になる可能性があります。ちょっとそれはできません。PostgreSQLで問題なく動作します: ->sqlfiddle
また、相関サブクエリから複数の列を返すことができればより簡単になりますが、MySQL でそれを行う方法がわかりません。
また、 CTEとウィンドウ関数を使用するとはるかに簡単になりますが、MySQL はこれらの最新の SQL 機能を認識していません (他の関連する RDBMS とは異なります)。