2017-10-13 5 views
0

私は、オンザフライで計算する必要があるデータを表示しようとすると少し厄介ですが、SELECTがあります。非常に遅いサブクエリを使用して選択を最適化する

データはSmartHomeシステムから記録され、可視化ソリューションGrafanaに表示されます。 私はこのすべてをMySQLで処理しなければならず、この作業の一部を行うためにデータやフロントエンドを実際に編集することはできません。

図には、UIで選択できる時間範囲の1日あたりの平均温度が表示されます。 MySQLで データはそのようなテーブルです:

DEVICE |  READING  |  VALUE  |  TIMESTAMP 
----------------------------------------------------------------------------- 
Thermometer |  temperature  |  20.0  | 2107.10.12 00:12:59 
Thermometer |  temperature  |  20.2  | 2107.10.12 00:24:12 
            ... 

要求は、最初の約10年ごとに完全な時間のタイムスタンプで(つまり、データベースにない)仮想テーブルを作成します。 これは非常に速く実行されていて、遅いフェッチの理由ではないようです。

その後、私は仮想テーブルを私のダイアグラムの可視時間範囲内の値に細分化します。 これらのフルタイム・タイムスタンプのすべてで、サブ・セレクトを実行して1時間前に記録された最後の温度値を取得する必要があります。

この値は、1日ごとにグループ化され、平均値が計算されます。 そのようにして、00:00から23:00までの1時間ごとの平均値は24以上になります。 異なる湿度場に基づいて、これは公式平均温度が通常計算される方法です。

SELECT 
    filtered.hour as time, 
    AVG((SELECT VALUE 
     FROM history 
     WHERE READING="temperature" AND DEVICE="Thermometer" AND TIMESTAMP <= filtered.hour 
     ORDER BY TIMESTAMP DESC 
     LIMIT 1 
    )) as value 
FROM (
    SELECT calculated.hour as hour FROM (
      SELECT DATE_ADD(DATE_SUB(DATE($__timeTo()), INTERVAL 10 YEAR), INTERVAL t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i HOUR) as hour 
      FROM (SELECT 0 as i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0, 
        (SELECT 0 as i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1, 
        (SELECT 0 as i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2, 
        (SELECT 0 as i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3, 
        (SELECT 0 as i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4 
    ) calculated 
    WHERE calculated.hour >= $__timeFrom() AND calculated.hour <= $__timeTo() 
) filtered 
GROUP BY DATE(filtered.hour) 

図を表示することが既に約5〜10秒かかり週のタイムスパンの場合:

はここでSELECT文です。あなたは1ヶ月近く30分近くです。 他のすべての(計算のない単純なフェッチ)ダイアグラムは、約1秒以内に読み込まれます。

私は完全にMySQLのnoobであり、自分のスマートな家のためにいくつかのSELECTを作成し始めたので、これをどう改善できるかは本当に分かりません。

プロの意見はありますか? :)

+0

これは間違いなく答えですが、特定の時系列データベースを使用する必要がありますか? Graphite https://graphiteapp.org/には統計機能があり、Influxdb(https://www.influxdata.com/time-series-platform/influxdb/)にはSQLのような構文があり、またプロメテウスなどがあります。そのようなソリューションの優れた点 - メトリックを扱うために設計されたもので、mysqlよりも長い時間をクエリするとずっと速くなります –

+0

1日に24回測定する必要がありますか? –

+0

@PeterM私は測定の量がそれほど重要でないとは思わない。私は6以上のものは良い結果を与えるべきだと思う、それは正式な計算からあまり変わらない。 大きな問題は、1日に等間隔でなければならないということです。さもなければ、あなたはたぶん、夜や1日を重くしすぎて、偽の結果をもたらすでしょう。 これは、フルタイムのタイムスタンプで「仮想テーブル」を作成した理由です。 – Thyraz

答えて

0

本当に明白な何かを監督していない限り、1日あたりの平均結果数を計算しても問題はありません。クエリを単純化してサブクエリを取り除くことができます。これはまた、あなたにスピードの向上をもたらすはずです。

SELECT DATE(`TIMESTAMP`) AS `date`, AVG(`VALUE`) AS `value` FROM `history` WHERE `READING`='temperature' AND `DEVICE`='Thermometer' AND DATE(`TIMESTAMP`) BETWEEN 'date1' AND 'date2' 

ただ、たとえば2017-10-15のために、必要な値でdate1 & date2を交換してください。

+0

これは基本的に最初の試行で行ったことですが、少なくとも1日分のグループ分けを見逃しています。 それ以外の場合は、毎日の値を持つテーブルではなく、時間範囲全体で1つの値を返しますか?しかし、主な問題は、1日に均等に分配される値を決定しないということです。だから、私が日より夜に記録される温度変化がもっとあると、平均気温が低くなりすぎます。 – Thyraz

+0

結果は、2つの日付間の各日の平均である必要があります。測定の量または間隔を考慮していません。測定値は一定の間隔で記録されていませんか? –

+0

いいえ、悲しいことに、変更が検出されたときにログに記録されます。 : -/ これは、毎時のタイムスタンプを作成し、最後に最後にログに記録した値を検索する理由のすべてです。 本当に正しい値を計算する方法が実際より速いのではないかと心配しています。 – Thyraz

関連する問題