L'un des indicateurs de trace SQL Server qui existe depuis un certain temps est 2389. Il est souvent discuté avec 2390, mais je veux juste me concentrer sur 2389 pour ce post. L'indicateur de trace a été introduit dans SQL Server 2005 SP1, qui a été publié le 18 avril 2006 (selon http://sqlserverbuilds.blogspot.co.uk/), il existe donc depuis plus de 10 ans. Les drapeaux de trace modifient le comportement du moteur, et 2389 permet à l'optimiseur d'identifier les statistiques qui sont ascendantes et de les marquer comme telles (souvent appelées "le problème de la clé ascendante"). Lorsque cela se produit, les statistiques sont automatiquement mises à jour au moment de la compilation de la requête, ce qui signifie que l'optimiseur dispose d'informations sur la valeur la plus élevée de la table (par rapport au cas où l'indicateur de trace n'est pas utilisé).
J'ai récemment eu une discussion avec un client sur l'utilisation de cet indicateur de trace, et elle est apparue à cause de ce type de scénario :
- Vous avez une grande table qui a un INT comme clé primaire, et elle est groupée.
- Vous avez un index non clusterisé qui mène sur une colonne DATETIME.
- Le tableau contient environ 20 millions de lignes, et entre 5 000 et 100 000 lignes sont ajoutées chaque jour.
- Les statistiques sont mises à jour chaque nuit dans le cadre de votre tâche de maintenance.
- Les statistiques de mise à jour automatique sont activées pour la base de données, mais même si 100 000 lignes sont ajoutées à la table, c'est bien moins que les 4 millions de lignes (20 %) nécessaires pour invoquer une mise à jour automatique.
- Lorsque les utilisateurs interrogent la table à l'aide de la date dans le prédicat, les performances des requêtes peuvent être excellentes, ou pas terribles.
Cette dernière puce fait presque penser à un problème de sensibilité des paramètres, mais ce n'est pas le cas. Dans ce cas, c'est un problème de statistiques. Ma suggestion au client était d'utiliser TF 2389 ou de mettre à jour les statistiques plus fréquemment tout au long de la journée (par exemple via un travail d'agent). Ensuite, j'ai pensé faire des tests, car le client exécutait SQL Server 2014. C'est là que les choses sont devenues intéressantes.
La configuration
Nous allons créer la table susmentionnée pour les tests dans la version RTM de SQL Server 2016, dans la base de données WideWorldImporters, et je vais initialement définir le mode de compatibilité sur 110 :
USE [master];GORESTORE DATABASE [WideWorldImporters]FROM DISK =N'C:\Backups\WideWorldImporters-Full.bak'WITH FILE =1,MOVE N'WWI_Primary' TO N'C:\Databases\WideWorldImporters\WideWorldImporters .mdf',MOVE N'WWI_UserData' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',MOVE N'WWI_Log' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.ldf',MOVE N'WWI_InMemory_Data_1' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_InMemory_Data_1', NOUNLOAD, REPLACE, STATS =5 ; ALLEZ ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =110 ; ALLEZ UTILISER [WideWorldImporters] ; ALLEZ CRÉER UNE TABLE [Sales].[BigOrders]([OrderID ] [int] NON NULL,[IDClient] [int] NON NULL,[SalespersonPersonID] [int] NON NULL,[PickedByPersonID] [int] NULL,[ContactPersonID] [int] NON NULL,[BackorderOrderID] [int] NULL, [OrderDate] [date] NON NULL,[ExpectedDeliveryDate] [date] NON NULL,[CustomerPurchaseOrderNumber] [nvarchar](20) NULL,[IsUndersupplyBackordered] [bit] NON NULL,[Commentaires] [nvarchar ](max) NULL,[DeliveryInstructions] [nvarchar](max) NULL,[InternalComments] [nvarchar](max) NULL,[PickingCompletedWhen] [datetime2](7) NULL,[LastEditedBy] [int] NOT NULL,[LastEditedWhen ] [datetime2](7) NOT NULL,CONSTRAINT [PK_Sales_BigOrders] PRIMARY KEY CLUSTERED([OrderID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [USERDATA]) SUR [USERDATA] TEXTIMAGE_ON [USERDATA] ;
Ensuite, nous allons charger environ 24 millions de lignes dans BigOrders et créer un index non clusterisé sur OrderDate.
SET NOCOUNT ON ; DÉCLARER @Loops SMALLINT =0, @IDIncrement INT =75000 ; WHILE @Loops <325 -- ajustez ceci pour augmenter ou diminuer le nombre de lignes ajoutéesBEGININSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], [OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + @IDIncrement,[CustomerID ],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders] ; POINT DE CONTRÔLE; SET @Loops =@Loops + 1;SET @IDIncrement =@IDIncrement + 75000;END CREATE NONCLUSTERED INDEX [NCI_BigOrders_OrderDate]ON [Sales].[BigOrders] ([OrderDate], CustomerID);
Si nous vérifions l'histogramme pour l'index non clusterisé, nous voyons que la date la plus élevée est 2016-05-31 :
DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);
Statistiques pour le NCI à la date de commande
Si nous recherchons une date ultérieure, notez le nombre estimé de lignes :
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Prévoyez une requête pour une date au-delà de ce qui est dans l'histogramme
C'est 1, car la valeur est en dehors de l'histogramme. Et dans ce cas, ce n'est pas grave, car il n'y a pas de lignes dans le tableau après le 31 mai 2016. Mais ajoutons-en quelques-unes, puis réexécutons la même requête :
INSÉRER [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25000000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-01',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]DE [Sales] .[Orders];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Planifier après l'ajout de lignes après le 31 mai
Le nombre estimé de lignes est toujours de 1. Mais c'est là que les choses deviennent intéressantes. Changeons le mode de compatibilité en 130 afin d'utiliser le nouvel estimateur de cardinalité et voyons ce qui se passe.
USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =130GO USE [WideWorldImporters];GO SELECT CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Planifiez après avoir ajouté des lignes pour le 1er juin, en utilisant le nouveau CE
Notre forme de plan est la même, mais maintenant notre estimation est de 4 898 lignes. Le nouveau CE traite les valeurs en dehors de l'historique différemment de l'ancien CE. Alors… avons-nous même besoin de l'indicateur de trace 2389 ?
Le test – Partie I
Pour le premier test, nous allons rester en mode de compatibilité 110 et passer en revue ce que nous verrions avec 2389. Lorsque vous utilisez cet indicateur de trace, vous pouvez soit l'activer en tant que paramètre de démarrage dans le service SQL Server, soit utiliser DBCC TRACEON pour l'activer à l'échelle de l'instance. Comprenez que dans votre environnement de production, si vous utilisez DBCC TRACEON pour activer l'indicateur de trace, lorsque l'instance redémarre, l'indicateur de trace ne sera pas effectif.
Avec l'indicateur de trace activé, une statistique doit être mise à jour trois (3) fois avant que l'optimiseur ne la marque comme ascendante. Nous allons forcer quatre mises à jour pour faire bonne mesure et ajouter plus de lignes entre chaque mise à jour.
UTILISER [maître];ALLER ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =110;ALLER DBCC TRACEON (2389, -1);ALLER UTILISER [WideWorldImporters];ALLER METTRE À JOUR LES STATISTIQUES [Sales].[BigOrders] [NCI_BigOrders_OrderDate];ALLER INSÉRER [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[ Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25100000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], '2016-06-02',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders] ];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID ],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [LastEditedBy][LastEditedWhen])SELECT[OrderID] + 25200000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-03',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber], [IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate] ; GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered], [Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy] ,[LastEditedWhen])SELECT[OrderID] + 25300000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-04',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate] ;Si nous vérifions à nouveau les statistiques et utilisons l'indicateur de trace 2388 pour afficher des informations supplémentaires, nous constatons que la statistique est maintenant marquée comme Croissante :
DBCC TRACEON (2388);GO DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);
NCI sur OrderDate marqué comme ASCSi nous recherchons une date future, lorsque les statistiques sont entièrement à jour, nous constatons qu'il estime toujours 1 ligne :
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Plan après TF 2389 activé, mais aucune ligne au-delà de l'histogrammeNous allons maintenant ajouter des lignes pour le 5 juin et réexécuter la même requête :
INSÉRER [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25400000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-05',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]DE [Sales] .[Orders];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Plan après TF 2389 activé, plus de 70 000 lignes ajoutées au-delà de l'histogrammeNotre estimation n'est plus 1, c'est 22 595. Maintenant, juste pour le plaisir, désactivons l'indicateur de trace et voyons quelle est l'estimation (je vais vider le cache de la procédure, car la désactivation de l'indicateur de trace n'affectera pas ce qui est actuellement dans le cache).
DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planifier après que TF 2389 soit * désactivé *, plus de 70 000 lignes ajoutées au-delà histogrammeCette fois-ci, j'obtiens à nouveau une estimation de 1 ligne. Même si la statistique est marquée comme ascendante, si l'indicateur de trace 2389 n'est pas activé, il n'estime qu'une ligne lorsque vous recherchez une valeur en dehors de l'histogramme.
Nous avons démontré que l'indicateur de trace 2389 fait ce que nous attendons - ce qu'il a toujours fait - lors de l'utilisation de l'ancien estimateur de cardinalité. Voyons maintenant ce qui se passe avec le nouveau.
Le test – Partie II
Pour être complet, je vais tout réinitialiser. Je vais recréer la base de données, définir le mode de compatibilité sur 130, charger les données initialement, puis activer l'indicateur de trace 2389 et charger trois ensembles de données avec des mises à jour de statistiques entre les deux.
USE [master];GO RESTORE DATABASE [WideWorldImporters]FROM DISK =N'C:\Backups\WideWorldImporters-Full.bak'WITH FILE =1,MOVE N'WWI_Primary' TO N'C:\Databases\WideWorldImporters\ WideWorldImporters.mdf',MOVE N'WWI_UserData' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',MOVE N'WWI_Log' TO N'C:\Databases\WideWorldImporters\WideWorldImporters.ldf',MOVE N'WWI_InMemory_Data_1' TO N'C:\Databases\WideWorldImporters\WideWorldImporters_InMemory_Data_1',NOUNLOAD, REPLACE, STATS =5;GO USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =130;GO USE [WideWorldImporters];GO CREATE TABLE [Sales] .[BigOrders]([OrderID] [int] NON NULL,[CustomerID] [int] NON NULL,[SalespersonPersonID] [int] NON NULL,[PickedByPersonID] [int] NULL,[ContactPersonID] [int] NON NULL,[ BackorderOrderID] [int] NULL,[OrderDate] [date] NOT NULL,[ExpectedDeliveryDate] [date] NOT NULL,[CustomerPurchaseOrderNumber] [nvarchar](20) NULL,[IsUndersupplyBackordered] [bit] NOT NULL,[Co commentaires] [nvarchar](max) NULL,[DeliveryInstructions] [nvarchar](max) NULL,[InternalComments] [nvarchar](max) NULL,[PickingCompletedWhen] [datetime2](7) NULL,[LastEditedBy] [int] NON NULL,[LastEditedWhen] [datetime2](7) NOT NULL,CONSTRAINT [PK_Sales_BigOrders] PRIMARY KEY CLUSTERED([OrderID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [USERDATA]) ON [USERDATA] TEXTIMAGE_ON [USERDATA];GO SET NOCOUNT ON ; DECLARE @Loops SMALLINT =0;DECLARE @IDIncrement INT =75000; WHILE @Loops <325 -- ajustez ceci pour augmenter ou diminuer le nombre de lignes ajoutéesBEGININSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], [OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + @IDIncrement,[CustomerID ],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders] ; POINT DE CONTRÔLE; SET @Loops =@Loops + 1;SET @IDIncrement =@IDIncrement + 75000;END CREATE NONCLUSTERED INDEX [NCI_BigOrders_OrderDate]ON [Sales].[BigOrders] ([OrderDate], CustomerID);GO INSERT [Sales].[BigOrders] ( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[ Commentaires internes],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25000000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-01', [ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO DBCC TRACEON (2389, -1);GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[Salesperson PersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy] ,[LastEditedWhen])SELECT[OrderID] + 25100000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-02',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires ],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedW hen])SELECT[OrderID] + 25200000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-03',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered], [Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];ALLER METTRE À JOUR LES STATISTIQUES [Ventes].[BigOrders] [NCI_BigOrders_OrderDate];ALLER INSÉRER [Ventes] ].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires], [DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25300000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016- 06-04',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalCo commentaires],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];Ok, donc nos données sont complètement chargées. Si nous vérifions à nouveau les statistiques et utilisons l'indicateur de trace 2388 pour afficher des informations supplémentaires, nous constatons que la statistique est à nouveau marquée comme Croissante :
DBCC TRACEON (2388);GO DBCC SHOW_STATISTICS ('Sales.BigOrders',[NCI_BigOrders_OrderDate]);
Statistique NCI OrderDate marquée comme ASC avec TF 2389 et mode de compatibilité 130Ok, reprenons la requête pour le 5 juin :
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planifiez avec le nouveau CE, pas de lignes au-delà de ce qui est dans l'histogrammeNotre estimation est de 4 922. Pas tout à fait ce qu'il était dans notre premier test, mais certainement pas 1. Maintenant, nous allons ajouter quelques lignes pour le 5 juin et relancer la requête :
INSÉRER [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25400000,[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-05',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Commentaires],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]DE [Sales] .[Orders];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planifiez avec le nouveau CE, avec plus de 70 000 lignes au-delà de ce qui se trouve dans l'histogrammeL'estimation est la même. Alors maintenant, que se passe-t-il si nous désactivons l'indicateur de trace 2389 ?
DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT CustomerID, OrderID, SalespersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planifiez avec le nouveau CE mais TF 2389 n'est PAS activé, avec 70K+ lignes au-delà de ce qui est dans l'histogrammeL'estimation a légèrement changé, à 4 930, mais elle a changé. Cela me dit que l'indicateur de trace 2389 a un certain effet sur l'estimation, mais combien est inconnu.
Le test – Partie III
J'ai exécuté un dernier test, où j'ai restauré la base de données, défini le mode de compatibilité sur 130, chargé à nouveau toutes les données, mis à jour les statistiques plusieurs fois, mais n'ai PAS activé l'indicateur de trace 2389. Le code est le même que la partie II, à l'exception de l'utilisation DBCC TRACEON pour activer 2389. Lorsque j'ai interrogé le 5 juin, avant et après l'ajout des données, le nombre estimé de lignes était de 4 920.
Qu'est-ce que cela signifie ?
Pour résumer, lors de l'utilisation du mode de compatibilité 110 ou inférieur, l'indicateur de trace 2389 fonctionne comme il l'a toujours fait. Mais lors de l'utilisation du mode de compatibilité 120 ou supérieur, et donc du nouveau CE, les estimations ne sont pas les mêmes par rapport à l'ancien CE, et dans ce cas précis, ne sont pas si différents que l'on utilise ou non l'indicateur de trace.
Alors, que devrais-tu faire? A tester, comme toujours. Je n'ai rien trouvé de documenté dans MSDN indiquant que l'indicateur de trace 2389 n'est pas pris en charge avec le mode de compatibilité 120 et supérieur, et je n'ai rien trouvé qui documente un changement de comportement. Je trouve très intéressant que les estimations soient différentes (dans ce cas beaucoup plus faibles) avec le nouveau CE. Cela pourrait potentiellement être un problème, mais il y a plusieurs facteurs en jeu lorsqu'il s'agit d'estimations, et c'était une requête très simple (une table, un prédicat). Dans ce cas, l'estimation est très erronée (4 920 lignes contre 22 595 lignes pour la date du 5 juin).
Si je relance la requête pour une date qui a le même nombre de lignes que est dans l'histogramme, j'obtiens un plan similaire, mais il s'exécute en parallèle :
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-02';
Planifier une requête qui utilise une date dans l'histogramme (nouveau CE, pas de TF)L'estimation est également plus précise (68 318). Le plan ne change pas de manière significative dans ce cas, mais le coût est évidemment plus élevé. À un moment donné, selon le nombre de lignes qui seraient renvoyées, cela pourrait basculer vers une analyse de table.
Le meilleur conseil à l'heure actuelle si vous utilisez 2014 ou supérieur et le mode de compatibilité 120 ou supérieur, et que vous avez des colonnes principales dans les statistiques qui augmentent, est de tester. Si vous trouvez que le nouvel estimateur de cardinalité ne fournit pas une estimation aussi bonne que l'ancien CE, je vous recommande de déposer un élément Connect afin que l'équipe produit en soit consciente. Il y a toujours des cas ponctuels et uniques, mais si de nombreux clients (lire :VOUS) constatent systématiquement le même comportement - et ce n'est pas idéal - alors il est important d'en informer l'équipe de développement.
Il s'agit d'un autre élément important à prendre en compte lors de la mise à niveau vers 2014 ou 2016 - et un rappel de ne pas négligez vos tests (et oh au fait, Query Store serait extrêmement utile ici avec 2016). Allez-y les amis.