Warum wird in dieser Abfrage nicht der Primärschlüssel (Clustered Key) verwendet?


10

Ich habe eine SQL Server 2008 R2-Tabelle, deren Schemastruktur wie folgt aussieht:

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

Und ich führe diese einfache Abfrage aus:

Select Max(Id)
From dbo.CDSIM_BE

Die Tabelle enthält ~ 2,5B Zeilen.

Der Abfrageplan zeigt einen Index-Scan, der für den IX_CdSIM_BE_ProbePositionIndex durchgeführt wird. Ich frage mich, warum SQL Server den Clustered- (und Primär-) Index einfach nicht verwenden und sofort zur letzten Zeile in der Tabelle gehen und den ID-Wert abrufen würde, da dies das Maximum sein muss.


Die Aggregate max () und min () sind in dieser Hinsicht häufig problematisch. Wenn Sie sicher sein möchten, dass ein Index verwendet wird, schreiben Sie stattdessenselect top 1 Id from dbo.CDSIM_BE order by Id descending;
Pieter Geerkens

4
Der Clustered-Index ist partitioniert, ReadTimesodass die von Ihnen beschriebene PK nicht verwendet werden kann. Es müsste das Max(Id)für jede Partition finden und dann das Maximum von diesen finden. Es ist möglich, die Abfrage neu zu schreiben, um einen Plan zu erhalten, auf den hier hingewiesen wird, obwohl dba.stackexchange.com/a/99418/3690
Martin Smith

Antworten:


7

Der Clustered-Index ist partitioniert, ReadTimesodass die von Ihnen beschriebene PK nicht verwendet werden kann. Es müsste das Max(Id)für jede Partition finden und dann das Maximum von diesen finden. Es ist jedoch möglich, die Abfrage neu zu schreiben, um einen solchen Plan zu erhalten.

Anhand eines Beispiels, das auf dem Artikel hier basiert, könnte ein mögliches Umschreiben sein

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; 

Jede Partition nacheinander verarbeiten.

Beachten Sie, dass der Plan noch einen Scan enthält (mit einem Suchprädikat zur Auswahl der Partition), dies jedoch kein vollständiger Scan der Partition ist.

Der Scan erfolgt in Indexreihenfolge mit der Richtung "BACKWARD". Der TOPIterator kann aufhören, Zeilen vom Scan anzufordern, nachdem die erste empfangen wurde.

Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.