¿Por qué no se usa la clave primaria (agrupada) en esta consulta?

10

Tengo una tabla de SQL Server 2008 R2 cuya estructura de esquema se ve de la siguiente manera:

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

Y estoy ejecutando esta simple consulta:

Select Max(Id)
From dbo.CDSIM_BE

Hay ~ 2.5B filas en la tabla.

El plan de consulta muestra una exploración de índice que se realiza en el IX_CdSIM_BE_ProbePositioníndice. Me pregunto por qué SQL Server simplemente no usaría el índice agrupado (y primario) e inmediatamente iría a la última fila de la tabla y recuperaría el valor Id, ya que ese debe ser el máximo.

Randy Minder
fuente
Los agregados max () y min () a menudo son problemáticos a este respecto. Si quiere estar seguro de que se utiliza un índice, escribaselect top 1 Id from dbo.CDSIM_BE order by Id descending;
Pieter Geerkens,
44
El índice agrupado está particionado ReadTimepara que no pueda usar la PK como usted describe. Tendría que encontrar el Max(Id)para cada partición y luego encontrar el máximo de esos. Es posible reescribir la consulta para obtener un plan como el mencionado aquí, aunque dba.stackexchange.com/a/99418/3690
Martin Smith

Respuestas:

7

El índice agrupado está particionado ReadTimepara que no pueda usar la PK como usted describe. Tendría que encontrar el Max(Id)para cada partición y luego encontrar el máximo de esos. Sin embargo, es posible reescribir la consulta para obtener dicho plan.

Usando un ejemplo basado en el artículo aquí, una posible reescritura podría 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 procesar cada partición a su vez.

Tenga en cuenta que el plan todavía tiene una exploración (con un predicado de búsqueda para seleccionar la partición) pero esta no es una exploración completa de la partición.

La exploración está en orden de índice con la dirección "HACIA ATRÁS". El TOPiterador puede dejar de solicitar filas del escaneo después de recibir el primero.

ingrese la descripción de la imagen aquí

Martin Smith
fuente