sql >> データベース >  >> RDS >> Database

トレースフラグ2389と新しいカーディナリティ推定量

    しばらくの間使用されてきたSQLServerトレースフラグの1つは2389です。これは2390でよく議論されますが、この投稿では2389に焦点を当てたいと思います。トレースフラグは、2006年4月18日にリリースされたSQL Server 2005 SP1(http://sqlserverbuilds.blogspot.co.uk/による)で導入されたため、10年以上前から存在しています。トレースフラグはエンジンの動作を変更し、2389を使用すると、オプティマイザは昇順の統計を識別し、そのようにブランド化できます(「昇順キーの問題」と呼ばれることがよくあります)。これが発生すると、統計はクエリのコンパイル時に自動的に更新されます。つまり、オプティマイザは、(トレースフラグが使用されていない場合と比較して)テーブルの最大値に関する情報を持っています。

    最近、このトレースフラグの使用についてクライアントと話し合いましたが、このタイプのシナリオが原因で発生しました:

    • 主キーとしてINTを持つ大きなテーブルがあり、クラスター化されています。
    • DATETIME列につながる非クラスター化インデックスがあります。
    • テーブルには約2,000万行が含まれ、毎日5,000〜100,000行が追加されます。
    • 統計は、メンテナンスタスクの一環として毎晩更新されます。
    • データベースの自動更新統計が有効になっていますが、テーブルに100,000行が追加されたとしても、自動更新を呼び出すために必要な400万行(20%)よりもはるかに少ないです。
    • ユーザーが述語の日付を使用してテーブルをクエリする場合、クエリのパフォーマンスが優れている場合もあれば、ひどい場合もあります。

    その最後の箇条書きは、ほとんどパラメータ感度の問題のように聞こえますが、そうではありません。この場合、それは統計の問題です。クライアントへの私の提案は、TF 2389を使用するか、1日を通してより頻繁に統計を更新することでした(たとえば、エージェントジョブを介して)。次に、クライアントがSQL Server 2014を実行していたので、いくつかのテストを行うと思いました。ここで、物事が面白くなりました。

    セットアップ

    WideWorldImportersデータベース内のSQLServer2016のRTMビルドでテストするための前述のテーブルを作成し、最初に互換モードを110に設定します。

    USE [master];
    GO
    RESTORE DATABASE [WideWorldImporters]
    FROM  DISK = N'C:\Backups\WideWorldImporters-Full.bak'
    WITH  FILE = 1,
    MOVE N'WWI_Primary' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.mdf',
    MOVE N'WWI_UserData' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',
    MOVE N'WWI_Log' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.ldf',
    MOVE N'WWI_InMemory_Data_1' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_InMemory_Data_1',
    NOUNLOAD, REPLACE, STATS = 5;
    GO
     
    ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL = 110;
    GO
     
    USE [WideWorldImporters];
    GO
     
    CREATE TABLE [Sales].[BigOrders](
    [OrderID] [int] NOT NULL,
    [CustomerID] [int] NOT NULL,
    [SalespersonPersonID] [int] NOT NULL,
    [PickedByPersonID] [int] NULL,
    [ContactPersonID] [int] NOT NULL,
    [BackorderOrderID] [int] NULL,
    [OrderDate] [date] NOT NULL,
    [ExpectedDeliveryDate] [date] NOT NULL,
    [CustomerPurchaseOrderNumber] [nvarchar](20) NULL,
    [IsUndersupplyBackordered] [bit] NOT NULL,
    [Comments] [nvarchar](max) NULL,
    [DeliveryInstructions] [nvarchar](max) NULL,
    [InternalComments] [nvarchar](max) NULL,
    [PickingCompletedWhen] [datetime2](7) NULL,
    [LastEditedBy] [int] NOT NULL,
    [LastEditedWhen] [datetime2](7) NOT NULL,
    CONSTRAINT [PK_Sales_BigOrders] PRIMARY KEY CLUSTERED
    (
    [OrderID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [USERDATA]
    ) ON [USERDATA] TEXTIMAGE_ON [USERDATA];

    次に、約2,400万行をBigOrdersにロードし、OrderDateに非クラスター化インデックスを作成します。

    SET NOCOUNT ON;
     
    DECLARE @Loops SMALLINT = 0, @IDIncrement INT = 75000;
     
    WHILE @Loops < 325 -- adjust this to increase or decrease the number of rows added
    BEGIN
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + @IDIncrement,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
     
    CHECKPOINT;
     
    SET @Loops = @Loops + 1;
    SET @IDIncrement = @IDIncrement + 75000;
    END
     
    CREATE NONCLUSTERED INDEX [NCI_BigOrders_OrderDate]
    ON [Sales].[BigOrders] ([OrderDate], CustomerID);

    非クラスター化インデックスのヒストグラムを確認すると、最高の日付は2016-05-31であることがわかります:

    DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);


    OrderDateのNCIの統計

    それ以降の日付をクエリする場合は、推定行数に注意してください。

    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-01';


    ヒストグラムにある日付以外の日付をクエリするときに計画する

    値がヒストグラムの外側にあるため、1です。この場合、2016年5月31日以降はテーブルに行がないため、問題ありません。ただし、いくつか追加してから、同じクエリを再実行してみましょう。

    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25000000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-01',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-01';


    5月31日を過ぎて行を追加した後に計画する

    推定行数はまだ1です。しかし、これが興味深いところです。互換モードを130に変更して、新しいカーディナリティ推定器を使用して何が起こるかを確認しましょう。

    USE [master];
    GO
     
    ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL = 130
    GO
     
    USE [WideWorldImporters];
    GO
     
    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-01';


    新しいCEを使用して、6月1日の行を追加した後に計画します

    計画の形状は同じですが、現在の見積もりは4,898行です。新しいCEは、履歴外の値を古いCEとは異なる方法で処理します。それで…トレースフラグ2389も必要ですか?

    テスト–パートI

    最初のテストでは、互換モード110を維持し、2389で表示される内容を実行します。このトレースフラグを使用する場合は、SQL Serverサービスの起動パラメーターとして有効にするか、DBCCを使用できます。 TRACEONを使用して、インスタンス全体で有効にします。本番環境では、DBCC TRACEONを使用してトレースフラグを有効にすると、インスタンスが再起動したときにトレースフラグが有効にならないことを理解してください。

    トレースフラグを有効にすると、オプティマイザが統計を昇順としてブランド化する前に、統計を3回更新する必要があります。適切な測定のために4つの更新を強制し、各更新の間に行を追加します。

    USE [master];
    GO
     
    ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL = 110;
    GO
     
    DBCC TRACEON (2389, -1);
    GO
     
    USE [WideWorldImporters];
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
    GO
     
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25100000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-02',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
    GO
     
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy]
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25200000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-03',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
    GO
     
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25300000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-04',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];

    統計を再度確認し、トレースフラグ2388を使用して追加情報を表示すると、統計が昇順としてマークされていることがわかります。

    DBCC TRACEON (2388);
    GO
     
    DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);


    ASCとしてマークされたOrderDateのNCI

    統計が完全に最新であるときに将来の日付を照会すると、1行が推定されていることがわかります。

    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-05';


    TF 2389を有効にしてから計画しますが、ヒストグラムを超える行はありません

    次に、6月5日の行を追加して、同じクエリを再度実行します。

    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25400000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-05',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-05';


    TF 2389を有効にしてから計画し、ヒストグラムを超えて70K以上の行を追加

    私たちの見積もりはもう1ではなく22,595です。さて、楽しみのために、トレースフラグを無効にして、見積もりが何であるかを見てみましょう(トレースフラグを無効にしても、現在キャッシュにあるものには影響しないため、プロシージャキャッシュをクリアします)。

    DBCC TRACEOFF (2389, -1);
    GO
     
    DBCC FREEPROCCACHE;
    GO
     
    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-05';


    TF 2389が*無効*になった後の計画、70K以上の行が追加されましたヒストグラム

    今回はまた1行の見積もりが出ます。統計は昇順としてブランド化されていますが、トレースフラグ2389が有効になっていない場合、ヒストグラムの外側の値をクエリすると、1行しか推定されません。

    古いCardinalityEstimatorを使用すると、トレースフラグ2389が期待どおりの動作(常に実行していたこと)を実行することを実証しました。それでは、新しいもので何が起こるか見てみましょう。

    テスト–パートII

    徹底的に、すべてをリセットします。データベースを再度作成し、互換モードを130に設定し、最初にデータをロードしてから、トレースフラグ2389をオンにして、統計情報の更新を間に挟んで3セットのデータをロードします。

    USE [master];
    GO
     
    RESTORE DATABASE [WideWorldImporters]
    FROM  DISK = N'C:\Backups\WideWorldImporters-Full.bak'
    WITH  FILE = 1,
    MOVE N'WWI_Primary' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.mdf',
    MOVE N'WWI_UserData' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',
    MOVE N'WWI_Log' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.ldf',
    MOVE N'WWI_InMemory_Data_1' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_InMemory_Data_1',
    NOUNLOAD, REPLACE, STATS = 5;
    GO
     
    USE [master];
    GO
     
    ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL = 130;
    GO
     
    USE [WideWorldImporters];
    GO
     
    CREATE TABLE [Sales].[BigOrders](
    [OrderID] [int] NOT NULL,
    [CustomerID] [int] NOT NULL,
    [SalespersonPersonID] [int] NOT NULL,
    [PickedByPersonID] [int] NULL,
    [ContactPersonID] [int] NOT NULL,
    [BackorderOrderID] [int] NULL,
    [OrderDate] [date] NOT NULL,
    [ExpectedDeliveryDate] [date] NOT NULL,
    [CustomerPurchaseOrderNumber] [nvarchar](20) NULL,
    [IsUndersupplyBackordered] [bit] NOT NULL,
    [Comments] [nvarchar](max) NULL,
    [DeliveryInstructions] [nvarchar](max) NULL,
    [InternalComments] [nvarchar](max) NULL,
    [PickingCompletedWhen] [datetime2](7) NULL,
    [LastEditedBy] [int] NOT NULL,
    [LastEditedWhen] [datetime2](7) NOT NULL,
    CONSTRAINT [PK_Sales_BigOrders] PRIMARY KEY CLUSTERED
    (
    [OrderID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON) ON [USERDATA]
    ) ON [USERDATA] TEXTIMAGE_ON [USERDATA];
    GO
     
    SET NOCOUNT ON;
     
    DECLARE @Loops SMALLINT = 0;
    DECLARE @IDIncrement INT = 75000;
     
    WHILE @Loops < 325 -- adjust this to increase or decrease the number of rows added
    BEGIN
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + @IDIncrement,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
     
    CHECKPOINT;
     
    SET @Loops = @Loops + 1;
    SET @IDIncrement = @IDIncrement + 75000;
    END
     
    CREATE NONCLUSTERED INDEX [NCI_BigOrders_OrderDate]
    ON [Sales].[BigOrders] ([OrderDate], CustomerID);
    GO
     
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25000000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-01',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    DBCC TRACEON (2389, -1);
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
    GO
     
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25100000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-02',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
    GO
     
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25200000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-03',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
    GO
     
    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25300000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-04',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];

    これで、データが完全に読み込まれました。統計を再度確認し、トレースフラグ2388を使用して追加情報を表示すると、統計が再び昇順としてマークされていることがわかります。

    DBCC TRACEON (2388);
    GO
     
    DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);


    NCI OrderDate統計は、TF2389および互換モード130でASCとしてマークされています

    では、6月5日についてもう一度質問しましょう:

    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-05';


    新しいCEで計画し、ヒストグラムの行を超える行はありません

    私たちの見積もりは4,922です。最初のテストでは完全ではありませんが、1ではありません。6月5日の行をいくつか追加して、再クエリします。

    INSERT [Sales].[BigOrders]
    ( [OrderID],
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    [OrderDate],
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    )
    SELECT
    [OrderID] + 25400000,
    [CustomerID],
    [SalespersonPersonID],
    [PickedByPersonID],
    [ContactPersonID],
    [BackorderOrderID],
    '2016-06-05',
    [ExpectedDeliveryDate],
    [CustomerPurchaseOrderNumber],
    [IsUndersupplyBackordered],
    [Comments],
    [DeliveryInstructions],
    [InternalComments],
    [PickingCompletedWhen],
    [LastEditedBy],
    [LastEditedWhen]
    FROM [Sales].[Orders];
    GO
     
    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-05';


    ヒストグラムの行数を70K以上超える、新しいCEで計画する

    見積もりは同じです。では、トレースフラグ2389をオフにするとどうなるでしょうか?

    DBCC TRACEOFF (2389, -1);
    GO
     
    DBCC FREEPROCCACHE;
    GO
     
    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-05';


    新しいCEで計画しますが、TF 2389は有効になっておらず、70K以上ですヒストグラムの行を超える行

    見積もりはわずかに変化して4,930になりましたが、変化しました。これは、トレースフラグ2389が見積もりに何らかの影響を与えることを示していますが、どの程度かは不明です。

    テスト–パートIII

    最後のテストを1つ実行しました。データベースを復元し、互換モードを130に設定し、すべてのデータを再度読み込み、統計を複数回更新しましたが、トレースフラグ2389を有効にしませんでした。コードはパートIIと同じですが、使用する点が異なります。 DBCC TRACEONで2389を有効にします。データを追加する前と後の両方で6月5日にクエリを実行したところ、推定行数は4,920でした。

    それはどういう意味ですか?

    要約すると、互換モード110以下を使用する場合、トレースフラグ2389はいつものように機能します。ただし、互換モード120以上、つまり新しいCEを使用している場合、見積もりはそうではありません 古いCEと比較して同じであり、この特定のケースでは、トレースフラグを使用するかどうかにかかわらずそれほど違いはありません。

    それで、あなたは何をすべきですか?いつものようにテストします。トレースフラグ2389が互換モード120以降ではサポートされていないことを示す、MSDNで文書化されたものは見つかりませんでした。また、動作の変更を文書化したものも見つかりませんでした。新しいCEとの見積もりが異なる(この場合ははるかに低い)ことは非常に興味深いと思います。これは潜在的に問題になる可能性がありますが、見積もりに関しては複数の要因が関係しており、これは非常に単純なクエリ(1つのテーブル、1つの述語)でした。この場合、見積もりはかなりずれています(6月5日の日付の22,595行に対して4920行)。

    と同じ行数の日付に対してクエリを再実行すると、 ヒストグラム内で、同様の計画が得られますが、並行して実行されます:

    SELECT CustomerID, OrderID, SalespersonPersonID
    FROM [Sales].[BigOrders]
    WHERE [OrderDate] = '2016-06-02';


    ヒストグラム内の日付を使用するクエリを計画します(新規CE、TFなし)

    見積もりもより正確です(68,318)。この場合、計画は大幅に変更されませんが、コストは明らかに高くなります。ある時点で、返される行の数によっては、これがテーブルスキャンに転じる可能性があります。

    2014以降および互換モード120以降を実行していて、統計の先頭の列が昇順である場合の現時点での最善のガイダンスは、テストすることです。新しいCardinalityEstimatorが古いCEほど適切な見積もりを提供しないことがわかった場合は、製品チームがそれを認識できるようにConnectアイテムを提出することをお勧めします。常に1回限りの固有のケースがありますが、多くの顧客(読み:YOU)が一貫して同じ動作を見つけ、それが理想的ではない場合は、開発チームにそのことを知らせることが重要です。

    これは、2014年または2016年にアップグレードする際に考慮すべきもう1つの重要な項目であり、しないことを忘れないでください。 テストを無視してください(ちなみに、クエリストアは2016年にここで非常に役立ちます)。友達に会いましょう。


    1. SQL自然結合

    2. Oracle SQL:列は許可されていません

    3. PostgreSQLのトップラーニング&トレーニングリソース

    4. 修正方法:JSON_VALUEは長い文字列でNULLを返します(SQL Server)