web-dev-qa-db-ja.com

かなり大きなテーブル(2分)での不正なクエリのインデックスヘルプ

何か助けを求めています。かなり大きなテーブル(200万レコード)に対して実行されているクエリがあります。

私はインデックスが効率的に機能するように努めています。このテーブルに対するクエリは他にもいくつかありますが、これが圧倒的に最も頻繁なクエリです。私はそれを1秒未満で実行するのに真剣に取り組んでおり、プロファイラーを使用して3〜5秒で実行されるのをよく見かけます。

可能な限り高速かもしれませんが、確認/拒否するための入力をお願いします。

注:開発者はクエリやスキーマをまったく変更しません。最適化はデータベースでのみ行うことができ、スキーマは変更されません。

テーブル:

CREATE TABLE [dbo].[Notifications](
[ntID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[NotificationID] [int] NOT NULL,
[NotificationType] [nvarchar](50) NOT NULL,
[UserName] [nvarchar](50) NULL,
[CreatedBy] [nvarchar](50) NULL,
[CreatedOn] [datetime] NULL,
[Status] [nvarchar](50) NOT NULL,
[Result] [nvarchar](50) NULL,
[Extension] [nvarchar](50) NULL,
[ShiftRate] [nvarchar](255) NULL,
[ResponseMinutes] [int] NULL,
[ResponseWindow] [datetime] NULL,
[caNotificationID] [int] NULL,
[AwardedBy] [nvarchar](50) NULL,
[AwardedOn] [datetime] NULL,
[CancelledBy] [nvarchar](50) NULL,
[CancelledOn] [datetime] NULL,
[CancelledReasonID] [int] NULL,
[CancelledReasonText] [nvarchar](255) NULL,
[AwardingDate] [datetime] NULL,
[ScheduledLaunchDate] [datetime] NULL,
[CustomMessage] [nvarchar](160) NULL,
[SystemName] [nvarchar](4000) NULL,
[AutoClose] [bit] NOT NULL,
 CONSTRAINT [PK_ESP_Notifications_ntID] PRIMARY KEY CLUSTERED 
(
    [ntID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[ESP_Notifications] ADD  DEFAULT ((0)) FOR [AutoClose]
GO

テーブルデータのスナップショット:

screenshot of sample data

クエリ:

Update Notifications 
  set Status = 'Awarding' OUTPUT deleted.* 
where ntID = (
    select top(1) ntID 
    from Notifications 
    where NotificationType = 'Shift' 
      and (Status = 'Done') 
      and ResponseWindow < '2019-02-04 10:40:03' 
    order by ntID)

試行されたインデックス:

CREATE INDEX [IX_Notifications_Status_NotificationType_ResponseWindow_ntID] 
ON [dbo].[Notifications](
   [Status] ASC,[NotificationType] ASC,[ResponseWindow] DESC,[ntID] DESC
)

CREATE INDEX [IX_Notifications_Status_ScheduledLaunchDate_ntID] 
ON [dbo].[Notifications](
    [ScheduledLaunchDate] DESC,[Status] ASC,[ntID] ASC
)

CREATE INDEX [IX_Notifications_NotificationType_caNotificationID_NotificationID_ntID] 
ON [dbo].[Notifications](
   [NotificationType] DESC, [caNotificationID] DESC, [NotificationID] DESC, [ntID] DESC
);

NotificationTypeには3つの異なるタイプが含まれ、そのうち70%はタイプ「Shift」ステータスが10タイプですが、「In Flight」レコードは約100から200のみで、4つのステータスに分割されます

ご協力いただきありがとうございます。

7
WadeH

その更新のサブクエリがこれら2つの述語値を一貫して使用する場合、フィルター選択されたインデックスが非常に役立ちます。次のようなもの(コメント Erik Darling を提供してください):

CREATE INDEX IX_ntID_ResponseWindow_Includes ON dbo.Notifications (ntID, ResponseWindow) 
INCLUDE (NotificationType, Status) 
WHERE (Status = 'Done' AND NotificationType = 'Shift');

これにより、サブクエリはStatusNotificationTypeに一致するIDの関連グループを検索し(インデックス内の唯一の行であるため)、データのソートを回避します(すでにntIDで並べ替えられているため)インデックスの先頭列)。

それは、各行のResponseWindow値をチェックする必要があります。最悪の場合、クエリの日付要件を満たす行がない場合(または最初の一致が非常に高いntIDである場合)、ほとんどまたはすべてのインデックスが読み取られます。そのため、このアプローチの効果はデータの配布に応じて制限されます。

15
Josh Darnell