Pourquoi la clé primaire (en cluster) n'est-elle pas utilisée dans cette requête?


10

J'ai une table SQL Server 2008 R2 dont la structure de schéma ressemble à ceci:

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

Et j'exécute cette simple requête:

Select Max(Id)
From dbo.CDSIM_BE

Il y a environ 2,5 milliards de lignes dans le tableau.

Le plan de requête montre une analyse d'index en cours sur l' IX_CdSIM_BE_ProbePositionindex. Je me demande pourquoi SQL Server n'utiliserait tout simplement pas l'index cluster (et principal) et irait immédiatement à la dernière ligne de la table et récupérerait la valeur Id, car cela devait être le maximum.


Les agrégats max () et min () sont souvent problématiques à cet égard. Si vous voulez être sûr qu'un index est utilisé, écrivez à la placeselect top 1 Id from dbo.CDSIM_BE order by Id descending;
Pieter Geerkens

4
L'index cluster est partitionné de ReadTimesorte qu'il ne pouvait pas utiliser le PK comme vous le décrivez. Il faudrait trouver le Max(Id)pour chaque partition, puis trouver le maximum de ceux-ci. Il est possible de réécrire la requête pour obtenir un tel plan comme mentionné ici via dba.stackexchange.com/a/99418/3690
Martin Smith

Réponses:


7

L'index cluster est partitionné de ReadTimesorte qu'il ne pouvait pas utiliser le PK comme vous le décrivez. Il faudrait trouver le Max(Id)pour chaque partition, puis trouver le maximum de ceux-ci. Il est cependant possible de réécrire la requête pour obtenir un tel plan.

En utilisant un exemple basé sur l'article ici, une réécriture possible pourrait être

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; 

Pour traiter chaque partition tour à tour.

Notez que le plan a toujours un scan (avec un prédicat de recherche pour sélectionner la partition) mais ce n'est pas un scan complet de la partition.

Le balayage est dans l'ordre d'index avec la direction "BACKWARD". L' TOPitérateur peut arrêter de demander des lignes à l'analyse une fois la première reçue.

entrez la description de l'image ici

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.