Por que a chave primária (em cluster) não está sendo usada nesta consulta?

10

Eu tenho uma tabela do SQL Server 2008 R2 cuja estrutura de esquema é a seguinte:

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])

E estou executando esta consulta simples:

Select Max(Id)
From dbo.CDSIM_BE

Existem ~ 2,5B linhas na tabela.

O plano de consulta mostra uma verificação de índice sendo feita no IX_CdSIM_BE_ProbePositioníndice. Eu estou querendo saber por que o SQL Server simplesmente não usaria o índice clusterizado (e primário) e imediatamente foi para a última linha da tabela e recuperou o valor de ID, pois esse deve ser o máximo.

Randy Minder
fonte
Os agregados max () e min () costumam ser problemáticos nesse sentido. Se você quer ter certeza de um índice é escrita usado em vezselect top 1 Id from dbo.CDSIM_BE order by Id descending;
Pieter Geerkens
4
O índice em cluster é particionado, ReadTimeportanto, não foi possível usar o PK como você descreve. Seria necessário encontrar o Max(Id)para cada partição e, em seguida, encontrar o máximo deles. É possível reescrever a consulta para obter esse plano um como aludido aqui, porém dba.stackexchange.com/a/99418/3690
Martin Smith

Respostas:

7

O índice em cluster é particionado, ReadTimeportanto, não foi possível usar o PK como você descreve. Seria necessário encontrar o Max(Id)para cada partição e, em seguida, encontrar o máximo deles. Ele é possível reescrever a consulta para obter esse plano um porém.

Usando um exemplo baseado no artigo aqui, uma possível reescrita pode ser

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; 

Para processar cada partição por vez.

Observe que o plano ainda possui uma varredura (com um predicado de busca para selecionar a partição), mas essa não é uma varredura completa da partição.

A varredura está na ordem do índice com a direção "BACKWARD". O TOPiterador pode parar de solicitar linhas da varredura após o recebimento da primeira.

insira a descrição da imagem aqui

Martin Smith
fonte