3

次のようなクエリがあります。

SELECT 
    ROUND(SUM(AGLR      * BlokInsideAreaFactor), 2) AS AGLRSum,
    ROUND(SUM(Vaarsaed  * BlokInsideAreaFactor), 2) AS VaarsaedSum,
    ROUND(SUM(Vintsaed  * BlokInsideAreaFactor), 2) AS VintsaedSum,
    ROUND(SUM(Oliefroe  * BlokInsideAreaFactor), 2) AS OliefroeSum,
    ROUND(SUM(Baelgsaed * BlokInsideAreaFactor), 2) AS BaelgsaedSum
    .... (+ 10 more columns)
FROM
(
    SELECT
        AGLR,         
        Vaarsaed,     
        Vintsaed,     
        Oliefroe,     
        Baelgsaed, 
        .... (+ 10 more columns)
        Round((CASE WHEN bloktema.AREAL > 0 THEN 
        omraade.Geom.STIntersection(bloktema.Geom).STArea() / bloktema.AREAL ELSE 0 END), 2) 
            AS BlokInsideAreaFactor
    FROM [CTtoolsData].dbo.BlokAfgroedeGrp blokAfgroed
    INNER JOIN [CTtoolsTema].dbo.bloktema2012 bloktema
        ON (bloktema.bloknr = blokAfgroed.bloknr)
    INNER JOIN [CTtoolsTema].dbo.Area omraade 
        ON omraade.Geom.STIntersects(bloktema.GEOM) = 1
    where   omraade.Id = 296
            AND blokAfgroed.[Year] = 2012
) AS Q1

ネストされた選択を行った理由は、「BlokInsideAreaFactor」を計算してから、外側の選択の他の列の値に乗算する必要があるためです。

「BlokInsideAreaFactor」は行ごとに 15 回 (列ごとに 1 回) 計算されるのではなく、行ごとに 1 回だけ計算されるため、この方法でクエリを最適化することを最初に考えました。問題は、このように実行すると、クエリが非常に遅くなるということです。約 4000 行を含むクエリには約 15 分かかります。残念ながら、ハードウェアが古くなっているため、SQLServer 2012 Express でクエリを実行しています。

私はインデックスを見てきましたが、そのようにさらに最適化することはできません。このように見えるクエリが非常に遅くなるのはなぜですか? 最も重要なのは、それを最適化する方法があることです。

アップデート:

関連するテーブルは次のようになります。

ブロックアフグローブグループ:

  • 列: Id (主キー、ID)、BlokNr、年、AGLR、Vaarsaed、Vintsaed...など。
  • インデックス: Id でクラスター化され、BlokNr + 年でクラスター化されていない一意のインデックス

ブロックテマ2012:

  • 列: Id (主キー、ID)、BlokNr、Geom (ジオメトリ) + その他 (重要ではない)
  • インデックス: Id でクラスター化、Geom で空間、非固有 - Id + BlokNr で非クラスター化、非固有 - BlokNr のみで非クラスター化。

領域:

  • 列: Id (主キー、ID)、Geom (ジオメトリ) + その他 (重要ではない)
  • インデックス: Id でクラスター化、Geom で空間

インデックスに断片化がないことを確認しました。

4

2 に答える 2

3

一時テーブルについて学んだ後、最近この質問に戻ってきました。私はこれにクエリを最適化することができました:

DECLARE @TempTable TABLE (AGLR float,         
    Vaarsaed float,     
    Vintsaed float,     
    Oliefroe float,     
    Baelgsaed float, 
    BlokInsideAreaFactor float)

INSERT INTO @TempTable (AGLR, Vaarsaed, Vintsaed, Oliefroe, Baelgsaed, BlokInsideAreaFactor)

SELECT
    AGLR,         
    Vaarsaed,     
    Vintsaed,     
    Oliefroe,     
    Baelgsaed,
    Round((CASE WHEN bloktema.AREAL > 0 THEN 
    omraade.Geom.STIntersection(bloktema.Geom).STArea() / bloktema.AREAL ELSE 0 END), 2) 
        AS BlokInsideAreaFactor
FROM [CTtoolsData].dbo.BlokAfgroedeGrp blokAfgroed
INNER JOIN [CTtoolsTema].dbo.bloktema2012 bloktema
    ON (bloktema.bloknr = blokAfgroed.bloknr)
INNER JOIN [CTtoolsTema].dbo.Area omraade 
    ON omraade.Geom.STIntersects(bloktema.GEOM) = 1
where   omraade.Id = 296
        AND blokAfgroed.[Year] = 2012


SELECT 
ROUND(SUM(AGLR      * BlokInsideAreaFactor), 2) AS AGLRSum,
ROUND(SUM(Vaarsaed  * BlokInsideAreaFactor), 2) AS VaarsaedSum,
ROUND(SUM(Vintsaed  * BlokInsideAreaFactor), 2) AS VintsaedSum,
ROUND(SUM(Oliefroe  * BlokInsideAreaFactor), 2) AS OliefroeSum,
ROUND(SUM(Baelgsaed * BlokInsideAreaFactor), 2) AS BaelgsaedSum
FROM @TempTable

...そのため、クエリは 15 分ではなく約 11 秒かかります。

それが他の誰かに役立つことを願っています!

于 2013-03-22T10:52:51.717 に答える
1

変数を宣言し、必要なデータセットまたは値を変数に入れ、変数を参照してすべての計算を実行してみませんか? 次に、その値を一度だけ見つける必要があります。

それをしたくない場合は、CTE (Common Table Expression)テーブルを作成して、句で何もせずにそのテーブルを参照して結合できるようにすることができます。where

SQL Server を使用していない場合は、一時テーブルの使用を検討できます。

于 2012-11-13T23:24:59.447 に答える