2

同様の問題を確認しましたが、どれもうまくいきませんでした。最も役に立ったのはhttp://forums.asp.net/t/1170815.aspx/1でしたが、パフォーマンスにより、クエリが何時間も実行されます。

4 年間の製品販売 (約 10,000 製品) に基づく 150 万件のレコードがあります。日付、製品、および 12 か月の売上を含むテーブルが必要です。

このクエリ(上記のリンクから)は機能し、私が望むものを示していますが、パフォーマンスは役に立たなくなります:

select day_key, product_key, price, (select sum(price) as R12 from #ORDER_TURNOVER as tb1 where tb1.day_key <= a.day_key and tb1.day_key > dateadd(mm, -12, a.day_key) and tb1.product_key = a.product_key) as RSum into #hejsan
from #ORDER_TURNOVER as a

すべてのレコードに対して非常に高速なローリング サム カーソル関数を試しましたが、過去 365 日間の売上を合計するだけのクエリを取得できませんでした。

この問題を解決する方法についてのアイデアは大歓迎です。ありがとうございました。

4

2 に答える 2

4

設定を少し変更します。

まず、関心のあるすべてのプロダクトキーを一覧表示するテーブルを用意します...

CREATE TABLE product (
  product_key    INT NOT NULL,
  price          INT,
  some_fact_data VARCHAR(MAX),
  what_ever_else SOMEDATATYPE,
  PRIMARY KEY CLUSTERED (product_key)
)

次に、レポートする必要のある個々の日付を含むカレンダーテーブルを作成します...

CREATE TABLE calendar (
  date             SMALLDATETIME,
  is_bank_holdiday INT,
  what_ever_else   SOMEDATATYPE,
  PRIMARY KEY CLUSTERED (date)
)

最後に、データテーブルに関連するすべてのフィールドのカバーインデックスがあることを確認します...

CREATE INDEX IX_product_day ON #ORDER_TURNOVER (product_key, day_key)

これにより、次のクエリが可能になります...

SELECT
  product.product_key,
  product.price,
  calendar.date,
  SUM(price)    AS RSum
FROM
  product
CROSS JOIN
  calendar
INNER JOIN
  #ORDER_TURNOVER AS data
    ON  data.product_key = product.product_key
    AND data.day_key    >  dateadd(mm, -12, calendar.date)
    AND data.day_key    <= calendare.date
GROUP BY
  product.product_key,
  product.price,
  calendar.date

このようにすべてを実行することにより、各product / calendar_dateの組み合わせは、すべて互いに連続しているデータテーブル内のレコードのセットに関連付けられます。これにより、集計するデータを検索する操作が、オプティマイザーにとってはるかに簡単になります。

[特に順序(製品、日付)で単一のインデックスが必要です。]

逆にインデックスがある場合、実際にははるかに困難です...

データ例:

 product | date                   date | product
---------+-------------    ------------+---------
    A    |  01/01/2012      01/01/2012 |    A
    A    |  02/01/2012      01/01/2012 |    B
    A    |  03/01/2012      02/01/2012 |    A
    B    |  01/01/2012      02/01/2012 |    B
    B    |  02/01/2012      03/01/2012 |    A
    B    |  03/01/2012      03/01/2012 |    B

左側のoyuは、365日ブロックで隣り合っているすべてのレコードを取得します。

右側では、集計する前に各レコードを検索します。検索は比較的簡単ですが、365回実行します。左のバージョンよりはるかに多い。

于 2012-05-22T12:51:53.200 に答える
1

これは、SQLServer2005-2008で「現在の合計」/「サブセットの合計」を実行する方法です。SQL 2012では、現在の合計をネイティブでサポートしていますが、2005〜2008年のデータベースを引き続き使用しています。

SELECT  day_key ,
        product_key ,
        price ,
        ( SELECT    SUM(price) AS R12
          FROM      #ORDER_TURNOVER AS tb1
          WHERE     tb1.day_key <= a.day_key
                    AND tb1.day_key > DATEADD(mm, -12, a.day_key)
                    AND tb1.product_key = a.product_key
        ) AS RSum
INTO    #hejsan
FROM    #ORDER_TURNOVER AS a 

いくつかの提案。

積算合計を事前に計算して、何度も計算されないようにすることができます。上記のselectは、偽装されたループであり、設定されたクエリではありません(オプティマイザがサブクエリを結合に変換できる場合を除く)。

上記のソリューションでは、コードにいくつかの変更を加える必要があります。

確かに試すことができるもう1つの解決策は、#ORDER_TURNOVER一時テーブルにクラスター化インデックスを作成することです。これはローカルな変更であるため、より安全です。

CREATE CLUSTERED INDEX IndexName
ON #ORDER_TURNOVER (day_key,day_key,product_key)

WHERE句の3つの式はすべてSARGSであるため、オプティマイザがスキャンではなくシークを実行するようになっています。

インデックスソリューションで十分なパフォーマンスの向上が得られない場合は、ソリューション1に投資する価値があります。

于 2012-05-22T12:36:40.817 に答える