1

産業機械からの監視データを含む巨大なテーブルがあります。テーブルには 30 個のいわゆるパラメーター列があり、典型的なクエリでは毎回 2 ~ 7 個が選択されます。その結果からグラフや状態表などが計算されます。ほとんどの計算では、指定された時間枠(メインデータ)の値に加えて、指定された時間枠(事前データ) の前のパラメーターの最新の非 null 値もわかっている必要があります。

現在、パラメーターごとに実行される事前データのクエリを使用しています。これは、 nが計算に必要なパラメーターの量である DB に n 個のクエリを導入するため、私が望むほど効率的ではありません。単一のクエリで事前データを取得することは何とか可能ですか (現在のクエリの例については、以下を参照してください)。

pre-data クエリの例 (fuel_cons、pwr_on、idle_counter に対しても実行):

SELECT
    alert_f335
FROM
    signal_value SIGV
    ,machine M /*Using old join since this is actually a Hibernate query*/
WHERE
    M.serialNumber = 'R451902'
    AND SIGV.machineId = M.id
    AND SIGV.time = (
        SELECT
            MAX(TMP.time)
        FROM
            signal_value TMP
        WHERE
            TMP.machineId = M.id
            AND TMP.time < 1370044800000 /*2013-06-01 00:00:00*/
            AND TMP.alert_f335 IS NOT NULL
    )
ORDER BY
    SIGV.time ASC

メインデータ クエリの例 (これで問題ありません):

SELECT
    alert_f335
    ,fuel_cons
    ,pwr_on
    ,idle_counter
FROM
    machine M
INNER JOIN
    signal_value SIGV
    ON M.id = SIGV.machineId
WHERE
    M.serialNumber = 'R451902'
    AND SIGV.time >= 1370044800000 /*2013-06-01 00:00:00*/
    AND SIGV.time <= 1371340799000 /*2013-06-15 23:59:59*/
    AND (alert_f335 IS NOT NULL OR fuel_cons IS NOT NULL OR pwr_on IS NOT NULL OR idle_counter IS NOT NULL)
ORDER BY
    SIGV.time ASC

machine テーブルには、id と serialNumber という 2 つの興味深い列があります。signal_value には、パラメーター列に加えて、2 つの興味深い列があります: machineId、time (ミリ秒)。

4

1 に答える 1

0

これは、結果がどこから返されるかによって異なります。プレデータ クエリで行っていることを見てみましょう。基本的に、alert_f335 が null でない 1 行 (およびその他のフィルター) を探しています。その行を A としましょう。次の列、fuel_cons について考えてみましょう。その行の正しい行が常に行 A である場合、それは簡単です。クエリの選択部分にすべてを貼り付けるだけです。しかし、この質問を投稿するのに苦労したので、それらは同じ行ではないと思います。

したがって、あるレベルでは、誰かが複数のクエリを実行する必要があります。現在行っているようにさまざまなクエリを送信してアプリケーション コードから実行するか、SQL Server に複数のクエリを実行するように依頼します。これらのクエリをサブクエリとして非表示にすることはできますが、最終的な結果として、SQL Server はこれを 4 回実行する必要があります。これらをうまく組み合わせると、実行計画にループがあるか、複数のブランチ (おそらく複数のブランチ) が平らになっていることがわかります。したがって、それらをマージしてもあまり得られません。

そうは言っても、あなたは少し得ることができます。これら 4 つのクエリはほとんどの部分で同じフィルターを共有するため、SQL Server にそれらが同じクエリであることを伝えることができるため、少なくともテーブル スプールまたはインデックス内のその場所を再利用するか、または実行することを決定します。優れたインデックスがあれば、それはほとんど問題になりません。書きやすいものは何でも使い続けます。

それらを実際にマージするには、CTE を使用してこの一時サブテーブルを作成し、4 つのサブクエリを使用してそれらをすべて同じ行に取得します。

with M as (
    select * from machine where id = 'R451902'
), TMP as (
    select * from signal_value 
    join M on M.id = signal_value.machineID
    where signal_value.time < 1370044800000
)
select 
    (select top 1 alert_f335 from TMP where alert_f335 is not null order by TMP.time DESC)
    ,(select top 1 fuel_cons from TMP where fuel_cons is not null order by TMP.time DESC)
    ,(select top 1 pwr_on  from TMP where pwr_on  is not null order by TMP.time DESC)
    ,(select top 1 idle_counter from TMP where idle_counter is not null order by TMP.time DESC)
于 2013-06-27T18:46:57.973 に答える