3

履歴テーブルからピボットされた結果セットを作成する次の SQL ステートメントを最適化しようとしています。これはすでに最も効率的な方法かもしれませんが、これを行うにはもっと効率的な方法が必要だと私は考え続けています。

最適化しようとしている SQL ステートメント

select Col1, Col2,
Max(case when TypeId = 1 then ColValue end) as Pivot1,
Max(case when TypeId = 2 then ColValue end) as Pivot2,
Max(case when TypeId = 3 then ColValue end) as Pivot3,
Max(case when TypeId = 4 then ColValue end) as Pivot4,
Max(case when TypeId = 5 then ColValue end) as Pivot5,
Max(case when TypeId = 6 then ColValue end) as Pivot6,
Max(case when TypeId = 7 then ColValue end) as Pivot7,
Max(case when TypeId = 8 then ColValue end) as Pivot8,
Max(case when TypeId = 9 then ColValue end) as Pivot9,
Max(case when TypeId = 10 then ColValue end) as Pivot10,
Max(case when TypeId = 11 then ColValue end) as Pivot11
from RowTable
group by Col1, Col2

更新:以下はテーブル定義です

CREATE TABLE dbo.RowTable  ( 
    Id                  int NOT NULL,
    Col1                char(8) NOT NULL,
    Col2                tinyint NOT NULL,
    TypeId              int NOT NULL,
    ColValue            datetime NOT NULL,
    CreatedBy           varchar(50) NOT NULL,
    Rowstamp            timestamp NOT NULL 
    )
LOCK DATAROWS
GO
ALTER TABLE dbo.RowTable
    ADD CONSTRAINT ukRowTable
    UNIQUE (Col1, Col2, TypeId)
    WITH max_rows_per_page = 0, reservepagegap = 0
4

2 に答える 2

1

元の質問への回答

1. テーブルを現状のままでのパフォーマンス。
さて、そのコードをパフォーマンスに関して評価する前に、インデックスを含む create table ステートメントが必要です。

  1. より高いクラスのパフォーマンス。
    ピボットは、利用可能なデータを行、列で表現する機能です。データベース (テーブル) が行指向の 3NF または 5NF に正規化されている場合、行オブジェクトに対する列関数の実行は遅くなります。商品とは関係ありません。列指向の高速アクセスが必要な場合 (ピボットまたはその他の列指向関数)、6NF のデータが必要です。これにより、タスクに必要な SQL がより簡単になります。

    データ モデラーがピボット用にテーブルを準備した場合 (通常、データ ウェアハウス タイプの使用法、Dimension-Fact 構造)、真の 6NF ではない可能性がありますが、少なくとも 5NF よりは優れており、ピボットされた値を簡単に抽出できます。DDL を見ると、それが何であるかを判断できます (真の 6NF。5NF よりは優れていますが、6NF ではありません)。次に、必要なものを取得するために最適なコードを使用しているかどうかを判断できます。

    テーブルが 6NF でない場合にのみ、低速または「高価」になります。

  2. この段階では、コードからはピボットのようにも見えず (用語の標準的な意味を使用)、MAX()さまざまな値のように見えます (結果の列を呼び出してPivotxもピボットにはなりません)。そして、あなたはすべての行を1回読んでいます。つまり、ピボットやセット指向の考え方ではなく、手続き型の考え方を持っているということです。したがって、コードは必要な値を取得できない可能性があります (パフォーマンスが良いかどうかは別の問題です)。

    を使用するGROUP BYと、非手続き型セットへの手続き型アプローチが確認されます。これは遅くなり (作業テーブルが作成されます。データが巨大な場合は巨大になります)、ディメンションを介して同じ情報をはるかに高速に取得できます。このピボット テーブルにディメンション テーブルを使用しませんか? このテーブルに関連するすべてのディメンション テーブルの DDL、またはデータ モデルを投稿します。

コメントへの対応

私はあなたを助けようとしていますが、2 つの障害があります。まず、やり取りの間隔は 19 日間です。次に、投稿された SQL は機能しません。行ごとにColValue、11 列で同じものを返します。の使用目的がわかりませんMAX()。わかりました。送信MAX()するには、を打ち負かす必要がありGROUP BYます。したがって、私はあなたが何を意図しているのか(あなたがコード化したものではない)についてまだ途方に暮れています。難読化は十分に公平ですが、ここでは意味が失われています。

はい、もっと速い方法がありますが、意図と親テーブルを理解する必要があります (たとえば、(Col1, Col2)一意のテーブルがありますか?データベースの場合、テーブルはスタンドアロンではなく、関連しており、関係には何らかの目的があります.関係があるとは思わないと思いますが、その制限により、投稿したコードが生成されます.解決策はその制限を超えています.

とにかく、これ以上の遅延を避けるために、このコードを試してください。それは単なる推測であり、私には正しくないように見えます(Col1, Col2, TypeId)。したがって、各結果行TypeIdには (結果セットの列見出し) のセットが 1 つだけ存在します。Col1, Col2

[Superceded, refer below]

そして、おそらくあなたはそれについて私にフィードバックを与えることができます.

更新された質問への回答

よし、正規化されていないテーブルが 1 つできました。新しい一連のステップ。これは、スカラーを返す相関サブクエリを使用して構築された結果セットです。行と列の再配置ではありません。これは標準のピボットではありません (したがって、提供されるコードはピボットではありません)。簡単に。人々は真のピボットを求めているため、質問の見出しを変更することをお勧めします。はい、これははるかに優れたパフォーマンスを発揮します (DDL が実際のテーブルの真の表現であると仮定します)。

明確にするために、ピボット (MS SQLPIVOT関数) は別の動物です。正規化されていないデータベースに醜くて遅いピボットを提供できます。または5NFデータベースからのクリーンだが遅いピボット。または6NFデータベースからのクリーンで高速なピボット。これはそうではありません。

  1. それがリレーショナル データベースであると仮定しましょう。提供された DDL を考えると、Unique である ParentTable が存在し(Col1, Col2)ます。

  2. コード:

    SELECT  Col1, 
        Col2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 1 ) as Latest_1,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 2 ) as Latest_2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 3 ) as Latest_3,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 4 ) as Latest_4,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 5 ) as Latest_5,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 6 ) as Latest_6,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 7 ) as Latest_7,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 8 ) as Latest_8,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 9 ) as Latest_9,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=10 ) as Latest_10,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=11 ) as Latest_11
    FROM ParentTable  OUTER

  3. ParentTable がない (つまり、リレーショナル データベースではない) 場合は、 でその場で作成するSELECT-INTOか、派生テーブルを使用します。

    SELECT  Col1, 
        Col2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 1 ) as Latest_1,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 2 ) as Latest_2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 3 ) as Latest_3,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 4 ) as Latest_4,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 5 ) as Latest_5,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 6 ) as Latest_6,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 7 ) as Latest_7,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 8 ) as Latest_8,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 9 ) as Latest_9,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=10 ) as Latest_10,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=11 ) as Latest_11
    FROM (
        SELECT DISTINCT
                Col1,
                Col2
            FROM RowTable
        )  OUTER

  4. IdRowTableの列を取り除くことができます。これは 100% 冗長な列とインデックスであり、何の役にも立ちません。

于 2010-11-28T00:47:41.523 に答える
0

ピボットは本質的にコストのかかる操作です。これは最適化できないと思います。

于 2010-11-26T13:16:15.960 に答える