2

ウィンドウ集計関数で RANGE オプションを使用すると、SQL Server 2012 で興味深い動作が発生します。これがバグなのか、SQL Server 2012 の「機能」なのかわかりません。次のように定義されたテーブルがあります。

CREATE TABLE [Test].[Trades](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Member] [varchar](20) NOT NULL,
    [TradeDate] [date] NOT NULL,
    [Fund] [varchar](4) NOT NULL,
    [Units] [decimal](28, 8) NOT NULL,
    PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )
);

このテーブルには、メンバーが特定の取引日にファンドで行った取引が格納されます。メンバーは、特定の日に特定のファンドで 1 回以上の取引を行うことができます。クラスター化インデックスに加えて、次のように定義された非クラスター化インデックスがあります。

CREATE NONCLUSTERED INDEX [Ix_TradesIndex] ON [Test].[Trades]
(
    [Member] ASC,
    [Fund] ASC,
    [TradeDate] ASC
)
INCLUDE ([Units]);

データ セットをクエリして、各メンバーが各ファンドで保有しているユニットの現在の合計を取得したい場合は、SQL Server 2012 のウィンドウ集計の拡張機能を使用して、次のように質問に答えることができます。

SELECT T.Member, T.Fund, T.TradeDate, 
SUM(T.Units) OVER(PARTITION BY T.Member, T.Fund
            ORDER BY T.TradeDate
            RANGE BETWEEN UNBOUNDED PRECEDING 
            AND CURRENT ROW) AS TotalShares
FROM Test.Trades AS T;

これにより、以下のようなデータ セットが得られます (例は、2005 年 2 月 3 日に Fund2 で 1 回以上の取引を行ったメンバーを示しています)。

....

メンバー 1、ファンド 1、2005 年 3 月 31 日、0.00

メンバー1、ファンド2、2005-02-03、3256.50

メンバー1、ファンド2、2005-02-03、3256.50

....

RANGE オプションは、注文句が一意でない場合 (つまり、特定のメンバーが特定の取引日に特定のファンドで複数の取引を行った場合)、ウィンドウが範囲の上部にあるすべての重複行を含むことを保証します。これは期待どおりに正しく機能しています。ただし、「このセットから個別の行のみを提供してください」(つまり、重複するエントリを削除する) と言いたい場合、この質問をする 1 つの方法は次のとおりです。

SELECT DISTINCT T.Member, T.Fund, T.TradeDate, T.TotalShares
FROM
(
    SELECT T.Member, T.Fund, T.TradeDate, 
        SUM(T.Units) OVER(PARTITION BY T.Member, T.Fund
                ORDER BY T.TradeDate
                RANGE BETWEEN UNBOUNDED PRECEDING 
                AND CURRENT ROW) AS TotalShares
    FROM Test.Trades AS T 
) AS T;

ここで興味深いことに、私が見ているのは、大規模なデータセットで計画が並行して行われた場合、結果のセットが非決定論的であるということです (つまり、クエリが間違った答えを返し、クエリが返す行数が後続の実行で変わる可能性があります)。クエリの)。 計画が並行に進まない場合(OPTION(MAXDOP 1) を指定することで明らかに強制できます)、クエリは常に同じ数の行を返し、結果セットが「正しい」場合は結果セットを返します。私には、これは SQL Server 2012 のバグのように感じます。

私の質問は、「<strong>誰かがこの動作について別の説明を持っていますか?それともこれはバグですか?」</p>

4

1 に答える 1

1

したがってRANGE、スプーリングにはディスク上の作業テーブルをROWS使用し、メモリ内を使用します(可能な場合)。私はスワップアウトして代わりにRANGE入れてみて、次のことを確認します:ROWS

  1. セマンティクスは同じです(たとえば、期待される結果が得られます)
  2. 計画は同じように変更されません(たとえば、常に期待される結果が得られます)

一部のクエリでは、これらは同じセマンティクスを与える可能性があり、他のクエリでは、基本的な意味を実際に変更する可能性があるため、この変更をテストする必要があることを再度強調します。セマンティクスが同じであれば、パフォーマンスが向上することをほぼ保証できます(そして、計画の偏りの可能性が低くなります)。

私はあなたが見つけた振る舞いがバグであるかどうかに異議を唱えているのではなく、あなたがそれを回避することができるかもしれない方法を提案しているだけです。ディスク上とメモリ内の相互作用が異なるという理由だけで、計画が並行するのを妨げる可能性があります。

これについてさらに詳しく調べたいと思います。データ入力スクリプトまたはバックアップをどこかに投稿して(明らかに独自のデータやプライベートデータがない場合)、これをより詳細に調査できますか?

于 2012-03-01T22:42:35.020 に答える