Perché la chiave primaria (in cluster) non viene utilizzata in questa query?


10

Ho una tabella di SQL Server 2008 R2 la cui struttura di schema ha il seguente aspetto:

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 sto eseguendo questa semplice query:

Select Max(Id)
From dbo.CDSIM_BE

Ci sono ~ 2.5B righe nella tabella.

Il piano di query mostra una scansione dell'indice in corso IX_CdSIM_BE_ProbePositionsull'indice. Mi chiedo perché SQL Server semplicemente non utilizzi l'indice cluster (e primario) e passi immediatamente all'ultima riga della tabella e recuperi il valore Id, poiché deve essere il massimo.


Gli aggregati max () e min () sono spesso problematici in questo senso. Se vuoi essere sicuro che venga usato un indice, scrivi inveceselect top 1 Id from dbo.CDSIM_BE order by Id descending;
Pieter Geerkens,

4
L'indice cluster è partizionato in ReadTimemodo da non poter usare il PK come descritto. Dovrebbe trovare il Max(Id)per ogni partizione e quindi trovare il massimo di quelli. È possibile riscrivere la query per ottenere un piano come indicato qui, anche se dba.stackexchange.com/a/99418/3690
Martin Smith,

Risposte:


7

L'indice cluster è partizionato in ReadTimemodo da non poter usare il PK come descritto. Dovrebbe trovare il Max(Id)per ogni partizione e quindi trovare il massimo di quelli. Si è possibile riscrivere la query per ottenere un tale piano però.

Utilizzando un esempio basato sull'articolo qui potrebbe essere una possibile riscrittura

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; 

Per elaborare ciascuna partizione a turno.

Nota che il piano ha ancora una scansione (con un predicato di ricerca per selezionare la partizione) ma questa non è una scansione completa della partizione.

La scansione è in ordine di indice con la direzione "BACKWARD". L' TOPiteratore può interrompere la richiesta di righe dalla scansione dopo aver ricevuto il primo.

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.