このクエリで主(クラスター)キーが使用されないのはなぜですか?


10

スキーマ構造が次のようなSQL Server 2008 R2テーブルがあります。

CREATE TABLE [dbo].[CDSIM_BE]
(
    [ID] [bigint] NOT NULL,
    [EquipmentID] [varchar](50) NOT NULL,
    [SerialNumber] [varchar](50) NULL,
    [PyrID] [varchar](50) NULL,
    [MeasMode] [varchar](50) NULL,
    [ReadTime] [datetime] NOT NULL,
    [SubID] [varchar](15) NULL,
    [ProbePosition] [float] NULL,
    [DataPoint] [int] NULL,

    CONSTRAINT [PK_CDSIM_BE] 
    PRIMARY KEY CLUSTERED ([ID] ASC, [EquipmentID] ASC, [ReadTime] ASC)
         WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
               IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
               ALLOW_PAGE_LOCKS = ON) ON [MonthlyArchiveScheme9]([ReadTime])
) ON [MonthlyArchiveScheme9]([ReadTime])

CREATE NONCLUSTERED INDEX [idx_CDSIM_BE__SubID_ProbePosition] 
ON [dbo].[CDSIM_BE] ([SubID] ASC, [ProbePosition] ASC)
INCLUDE ([EquipmentID], [ReadTime], [BECorr]) 
    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
          SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
          ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [MonthlyArchiveScheme9]([ReadTime])

CREATE NONCLUSTERED INDEX [IX_CDSIM_BE_ProbePosition] 
ON [dbo].[CDSIM_BE] ([ProbePosition] ASC)
INCLUDE ([SerialNumber], [SubID]) 
    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
          SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
          ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [MonthlyArchiveScheme9]([ReadTime])

CREATE NONCLUSTERED INDEX [IX_CSDIM_Readtime] 
ON [dbo].[CDSIM_BE]([ReadTime] ASC)
INCLUDE ([EquipmentID]) 
    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
          SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
          ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [MonthlyArchiveScheme9]([ReadTime])

そして、私はこの簡単なクエリを実行しています:

Select Max(Id)
From dbo.CDSIM_BE

テーブルには〜2.5B行あります。

クエリプランは、インデックスに対して実行されているインデックススキャンを示していIX_CdSIM_BE_ProbePositionます。SQL Serverが単にクラスター化(およびプライマリ)インデックスを使用せず、すぐにテーブルの最後の行に移動してId値を取得するのはなぜかと思います。


MAX()分()凝集体はこの点でしばしば問題となります。インデックスが確実に使用されるようにしたい場合は、代わりに書き込みselect top 1 Id from dbo.CDSIM_BE order by Id descending;
Pieter Geerkens

4
クラスター化インデックスはパーティション化されReadTimeているため、説明したようにPKを使用できませんでした。Max(Id)各パーティションのを見つけてから、それらの最大値を見つける必要があります。クエリを書き直して、dba.stackexchange.com / a / 99418/3690を介し
Martin Smith

回答:


7

クラスター化インデックスはパーティション化されReadTimeているため、説明したようにPKを使用できませんでした。Max(Id)各パーティションのを見つけてから、それらの最大値を見つける必要があります。ただし、そのようなプランを取得するためにクエリを書き換えること可能です。

ここの記事に基づく例を使用すると、可能な書き換えは

SELECT MAX(ID) AS ID
FROM   sys.partitions AS P
       CROSS APPLY (SELECT MAX(ID) AS ID
                    FROM   [dbo].[CDSIM_BE]
                    WHERE  $PARTITION.MonthlyArchiveFunction9(ReadTime) 
                                                    = P.partition_number) AS A
WHERE  P.object_id = OBJECT_ID('dbo.CDSIM_BE')
       AND P.index_id <= 1; 

各パーティションを順番に処理します。

プランにはまだスキャンがありますが(パーティションを選択するためのシーク述語を使用)、これはパーティションのフルスキャンではありません。

スキャンは「バックワード」方向のインデックス順です。TOPイテレータは、最初のものが受信された後、スキャンから行を要求して停止することができます。

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.