3

全体的な課題:

多くの「マーケット」について、1日に数回テーブルにアイテムを追加しています。

それで

  • 12:00に、マーケット「x」に2000アイテムを追加します。
  • 12:30に、マーケット「y」に3000アイテムを追加します。
  • 14:00に、マーケット「x」に2500アイテムを追加します。

これは毎日数回行われます。

いつでも、毎日の各市場の最新アイテムを抽出する必要があります

上記の挿入の望ましい結果は次のとおりです。

マーケット「x」の2500アイテム

マーケット「y」の3000アイテム

データのバッチを追加するたびに、バッチを一意に定義するExecutionTimeタイムスタンプがあります。したがって、12:00のマーケット「x」の2000アイテムは同じExecutionTime値を持ち、14:00のマーケット「x」の2500アイテムは別のExecutionTime値を持ちます。

私たちはこれを行うビューを作成しました

SELECT     
    *
FROM         
    dbo.Items AS s
WHERE     
    (ExecutionTime =
       (SELECT     MAX(ExecutionTime) AS Expr1
        FROM          dbo.Items AS s2
        WHERE      (SiteAlias = s.SiteAlias) AND (Market = s.Market) 
          AND (LocalTimestamp >= 
            DATEADD(dd, DATEDIFF(dd, 0, s.LocalTimestamp), 0)) 
          AND 
              (LocalTimestamp < 
            DATEADD(dd, DATEDIFF(dd, 0, s.LocalTimestamp), 1))))

次のようにビューをクエリします。

SELECT *
FROM [ExportedData]
WHERE 
  SiteAlias = 'MyAlias'
  AND LocalTimeStamp between '2012-05-14 00:00' AND '2012-05-18 00:00'
ORDER BY [Timestamp]

テーブルITemsのフィールドExecutiontimeにインデックスを定義し、sitealiasにインデックスとlocaltimestampを組み合わせたインデックスを定義しました。

問題:パフォーマンスが低下します。約150000行のクエリには数分かかります。

私たちがすべき見解に明らかな改善はありますか?ビューの作成で簡単な失敗がない場合に備えて、クエリプランなどを提供する準備ができています。

興味深いことに、SiteAliasで「=」の代わりに「LIKE」を使用してビューをクエリすると、実行が約90%高速化されます。これは私が予想していなかったことです。

ありがとう、

:o)

/ジェスパーコペンハーゲン

4

2 に答える 2

3

あなたのT-SQLとテーブルの構造は、一見すると私には問題ないように見えます-したがって、これは暗闇の中へのワイルドショットです:-)

私がおそらくあなたの立場で試みるのは、SQL Server 2008を使用しているので、CTE(共通テーブル式)を使用LocalTimestampしてデータ型にキャストすることです。DATE

それらを配置すると、次のようなビューを作成できます。

CREATE VIEW dbo.YourView
AS
   WITH DataPerDay AS
   (
      SELECT 
         *,
         RowNum = ROW_NUMBER() OVER (PARTITION BY CAST(LocalTimestamp AS DATE) 
                                     ORDER BY ExecutionTime DESC)
      FROM         
         dbo.Items AS s
   )
   SELECT *
   FROM DataPerDay 
   WHERE RowNum = 1

基本的に、CTEはデータを日付のみの部分で「パーティション化」し、LocalTimestampその日のすべてのエントリに1から始まる連続番号を割り当てます。したがって、1日あたりの「最新」または「最新」のエントリが取得RowNum = 1されます。そのCTEからの選択で使用します。

これはSELECT(MAX) ....サブクエリを回避し、私の個人的な観察では少し速いようですが、それはテーブルとデータに大きく依存しているので、自分で試してみて、それが役立つかどうかを確認してください!

于 2012-05-25T09:27:03.300 に答える
2

興味深いことに、SiteAliasで「=」の代わりに「LIKE」を使用してビューをクエリすると、実行が約90%高速化されます。これは私が予想していなかったことです。

うーん、それは確かに奇妙です。これは、根本的な問題の結果である可能性があります。

クエリは一貫して遅いですか、それともパフォーマンスの問題はしばらくしてから始まりますか?クエリの最後にOPTION(RECOMPILE)を追加して、「パラメータスニッフィング」を除外できますか?

SELECT *
FROM [ExportedData]
WHERE 
  SiteAlias = 'MyAlias'
  AND LocalTimeStamp between '2012-05-14 00:00' AND '2012-05-18 00:00'
ORDER BY [Timestamp]
OPTION (RECOMPILE)

あなたはテーブルが1日に数回追加されると言っています。SQL Serverは通常、統計を最新の状態に保つのに優れた仕事をしますが、オプティマイザーが間違った/データ外の統計を使用している可能性があります

  • このデータベースのAUTO_CREATE_STATISTICSはオンに設定されていますか?
  • パフォーマンスの遅いクエリのインスタンスを分離し、すべての統計を更新した後に実行させることはできますか?

同様の実行プランとクエリの=バージョンを確認するとよいでしょう。

アップデート1

推定実行計画のスクリーンショットを提供しました。実際の値(見積もりを含む)を確認する必要があります。また、スクリーンショットへの2番目のリンクは機能しません。

コメントに入れる代わりに、xmlプランで質問を更新できますか?これは、質問を検討している新しい人々にとってもより役立ちます。

"="バージョンの実行プランでは、推定行数が1の場合に100%がキールックアップに入るとはわかりません。それは意味がありません。

実際の実行のxml計画は確かに役立ちます。カーディナリティがオフになっている可能性があるため、実際の行数と推定行数の違いを確認できます。この場合、一時テーブルを使用すると、統計が正確であり、それにインデックスを付けることができるため、役立つ場合があります。

SELECT *
into #tempExportedData
FROM [ExportedData]

SELECT *
FROM #tempExportedData
WHERE 
  SiteAlias = 'MyAlias'
  AND LocalTimeStamp between '2012-05-14 00:00' AND '2012-05-18 00:00'
ORDER BY [Timestamp]
于 2012-05-25T09:18:00.863 に答える