Um dos sinalizadores de rastreamento do SQL Server que existe há algum tempo é 2389. É frequentemente discutido com 2390, mas quero focar apenas em 2389 para esta postagem. O sinalizador de rastreamento foi introduzido no SQL Server 2005 SP1, lançado em 18 de abril de 2006 (de acordo com http://sqlserverbuilds.blogspot.co.uk/), portanto, existe há mais de 10 anos. Os sinalizadores de rastreamento alteram o comportamento do mecanismo, e o 2389 permite que o otimizador identifique estatísticas que estão aumentando e as marque como tal (geralmente chamado de "o problema da chave ascendente"). Quando isso ocorrer, as estatísticas serão atualizadas automaticamente em tempo de compilação da consulta, o que significa que o otimizador tem informações sobre o valor mais alto da tabela (comparado a quando o sinalizador de rastreamento não é usado).
Recentemente, tive uma discussão com um cliente sobre o uso desse sinalizador de rastreamento e surgiu devido a esse tipo de cenário:
- Você tem uma tabela grande que tem um INT como chave primária e está agrupada.
- Você tem um índice não clusterizado que leva a uma coluna DATETIME.
- A tabela tem cerca de 20 milhões de linhas, e de 5.000 a 100.000 linhas são adicionadas a cada dia.
- As estatísticas são atualizadas todas as noites como parte de sua tarefa de manutenção.
- As estatísticas de atualização automática estão ativadas para o banco de dados, mas mesmo que 100.000 linhas sejam adicionadas à tabela, isso é muito menos do que os 4 milhões de linhas (20%) necessários para invocar uma atualização automática.
- Quando os usuários consultam a tabela usando a data no predicado, o desempenho da consulta pode ser ótimo ou ruim.
Essa última bala quase faz parecer um problema de sensibilidade de parâmetro, mas não é. Neste caso, é uma questão de estatística. Minha sugestão para o cliente foi usar o TF 2389 ou atualizar as estatísticas com mais frequência ao longo do dia (por exemplo, por meio de um trabalho de agente). Então pensei em fazer alguns testes, já que o cliente estava executando o SQL Server 2014. Foi aí que as coisas ficaram interessantes.
A configuração
Vamos criar a tabela mencionada para teste na compilação RTM do SQL Server 2016, dentro do banco de dados WideWorldImporters, e vou definir o modo de compatibilidade para 110 inicialmente:
USE [master];GORESTORE DATABASE [WideWorldImporters]FROM DISCO =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 ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =110;GO USE [WideWorldImporters];GO CREATE TABLE [Vendas].[BigOrders]([OrderID ] [int] NOT NULL,[CustomerID] [int] NOT NULL,[SalespersonID] [int] NOT NULL,[PickedByPersonID] [int] NULL,[ContactPersonID] [int] NOT NULL,[BackorderOrderID] [int] NULL, [OrderDate] [date] NOT NULL,[ExpectedDeliveryDate] [date] NOT NULL,[CustomerPurchaseOrderNumber] [nvarchar](20) NULL,[IsUndersupplyBackordered] [bit] NOT NULL,[Comments] [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]) ON [USERDATA] TEXTIMAGE_ON [USERDATA];
Em seguida, vamos carregar cerca de 24 milhões de linhas em BigOrders e criar um índice não clusterizado em OrderDate.
SET NOCOUNT ON; DECLARE @Loops SMALLINT =0, @IDIncrement INT =75000; WHILE @Loops <325 -- ajuste para aumentar ou diminuir o número de linhas adicionadasBEGININSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], [OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + @IDIncrement,[CustomerID ],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [Última edição por], [Última edição quando] DE [Vendas].[Pedidos]; PONTO DE VERIFICAÇÃO; SET @Loops =@Loops + 1;SET @IDIncrement =@IDIncrement + 75000;END CREATE NONCLUSTERED INDEX [NCI_BigOrders_OrderDate]ON [Sales].[BigOrders] ([OrderDate], CustomerID);
Se verificarmos o histograma do índice não clusterizado, veremos que a data mais alta é 31/05/2016:
DBCC SHOW_STATISTICS ('Vendas.BigOrders',[NCI_BigOrders_OrderDate]);
Estatísticas para o NCI em OrderDate
Se consultarmos qualquer data além dessa, observe o número estimado de linhas:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Vendas].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Planeje ao consultar uma data além da que está no histograma
É 1, porque o valor está fora do histograma. E, neste caso, tudo bem, porque não há linhas na tabela além de 31 de maio de 2016. Mas vamos adicionar algumas e executar novamente a mesma consulta:
INSERIR [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comentários],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25000000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-01',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen] DE [Vendas] .[Pedidos];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Vendas].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Planeje após adicionar linhas após 31 de maio
O número estimado de linhas ainda é 1. Mas é aí que as coisas ficam interessantes. Vamos alterar o modo de compatibilidade para 130 para usarmos o novo Estimador de cardinalidade e ver o que acontece.
USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =130GO USE [WideWorldImporters];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-01';
Planeje após adicionar linhas para 1º de junho, usando o novo CE
Nosso formato de plano é o mesmo, mas agora nossa estimativa é de 4.898 linhas. O novo CE trata valores fora do histórico de forma diferente do antigo CE. Então... precisamos mesmo do sinalizador de rastreamento 2389?
O Teste – Parte I
Para o primeiro teste, permaneceremos no modo de compatibilidade 110 e executaremos o que veríamos com 2389. Ao usar esse sinalizador de rastreamento, você pode habilitá-lo como um parâmetro de inicialização no serviço SQL Server ou usar DBCC TRACEON para habilitá-lo em toda a instância. Entenda que em seu ambiente de produção, se você usar DBCC TRACEON para habilitar o sinalizador de rastreamento, quando a instância reiniciar, o sinalizador de rastreamento não terá efeito.
Com o sinalizador de rastreamento ativado, uma estatística deve ser atualizada três (3) vezes antes que o otimizador a marque como crescente. Forçaremos quatro atualizações para uma boa medida e adicionaremos mais linhas entre cada atualização.
USE [master];GO ALTER DATABASE [WideWorldImporters] SET COMPATIBILITY_LEVEL =110;GO DBCC TRACEON (2389, -1);GO USE [WideWorldImporters];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Sales].[BigOrders]([OrderID],[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[ Comentários],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25100000,[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], '2016-06-02',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Vendas].[Pedidos ];GO UPDATE STATISTICS [Vendas].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Vendas].[BigOrders]( [OrderID],[CustomerID ],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [LastEditedBy][LastEditedWhen])SELECT[OrderID] + 25200000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-03',[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],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered], [Comentários],[Instruções de Entrega],[Comentários Internos],[PickingCompletedWhen],[LastEditedBy] ,[LastEditedWhen])SELECT[OrderID] + 25300000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-04',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comentários],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
Se verificarmos as estatísticas novamente e usarmos o sinalizador de rastreamento 2388 para exibir informações adicionais, veremos que a estatística agora está marcada como Crescente:
DBCC TRACEON (2388);GO DBCC SHOW_STATISTICS('Vendas.BigOrders',[NCI_BigOrders_OrderDate]);
NCI em OrderDate marcado como ASC
Se consultarmos uma data futura, quando as estatísticas estiverem totalmente atualizadas, veremos que ainda estima 1 linha:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Vendas].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planeje após o TF 2389 ativado, mas sem linhas além do histograma
Agora adicionaremos linhas para 5 de junho e executaremos a mesma consulta novamente:
INSERIR [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comentários],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25400000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-05',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen] DE [Vendas] .[Pedidos];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planeje após o TF 2389 ativado, mais de 70 mil linhas adicionadas além do histograma
Nossa estimativa não é mais 1, é 22.595. Agora, só por diversão, vamos desabilitar o sinalizador de rastreamento e ver qual é a estimativa (vou limpar o cache do procedimento, pois desabilitar o sinalizador de rastreamento não afetará o que está atualmente no cache).
DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planeje após o TF 2389 ser *desativado*, mais de 70 mil linhas adicionadas histograma
Desta vez, recebo uma estimativa de 1 linha novamente. Mesmo que a estatística seja marcada como crescente, se o sinalizador de rastreamento 2389 não estiver habilitado, ele estimará apenas 1 linha quando você consultar um valor fora do histograma.
Demonstramos que o sinalizador de rastreamento 2389 faz o que esperamos – o que sempre fez – ao usar o antigo Estimador de cardinalidade. Agora vamos ver o que acontece com o novo.
O Teste – Parte II
Para ser completo, vou redefinir tudo. Vou criar o banco de dados novamente, definir o modo de compatibilidade para 130, carregar os dados inicialmente, depois ativar o sinalizador de rastreamento 2389 e carregar três conjuntos de dados com atualizações de estatísticas entre eles.
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' PARA N'C:\Databases\WideWorldImporters\WideWorldImporters_UserData.ndf',MOVE N'WWI_Log' PARA 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 [Vendas] .[BigOrders]([OrderID] [int] NOT NULL,[CustomerID] [int] NOT NULL,[SalespersonID] [int] NOT NULL,[PickedByPersonID] [int] NULL,[ContactPersonID] [int] NOT NULL,[ BackorderOrderID] [int] NULL,[OrderDate] [date] NOT NULL,[ExpectedDeliveryDate] [date] NOT NULL,[CustomerPurchaseOrderNumber] [nvarchar](20) NULL,[IsUndersupplyBackordered] [bit] NOT NULL,[Co mments] [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]) ON [USERDATA] TEXTIMAGE_ON [USERDATA];GO SET NOCOUNT ON; DECLARE @Loops SMALLINT =0;DECLARE @IDIncrement INT =75000; WHILE @Loops <325 -- ajuste para aumentar ou diminuir o número de linhas adicionadasBEGININSERT [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID], [OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + @IDIncrement,[CustomerID ],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen], [Última edição por], [Última edição quando] DE [Vendas].[Pedidos]; PONTO DE VERIFICAÇÃO; 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],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[ InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25000000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-01', [ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO DBCC TRACEON (2389, -1);GO UPDATE STATISTICS [Vendas].[BigOrders] [NCI_BigOrders_OrderDate];GO INSERT [Vendas].[BigOrders]( [OrderID],[CustomerID],[Vendedor PersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy] ,[LastEditedWhen])SELECT[OrderID] + 25100000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-02',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comentários],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Vendas].[Pedidos];VÁ ATUALIZAR ESTATÍSTICAS [Vendas].[BigOrders] [NCI_BigOrders_OrderDate];VÁ INSERIR [Vendas].[BigOrders]( [OrderID],[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered], [Comentários ],[Instruções de Entrega],[Comentários Internos],[Seleção ConcluídaQuando],[Última EdiçãoPor],[Última EdiçãoW hen])SELECT[OrderID] + 25200000,[CustomerID],[SalespersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016-06-03',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered], [Comentários],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Vendas].[Pedidos];VÁ ATUALIZAR ESTATÍSTICAS [Vendas].[BigOrders] [NCI_BigOrders_OrderDate];VÁ INSERT [Vendas] ].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments], [DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25300000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],'2016- 06-04', [Data de Entrega Esperada], [Número do Pedido de Compra do Cliente], [Está em falta em falta], [Comentários], [Instruções de Entrega], [InternalCo mments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen]FROM [Sales].[Orders];GO UPDATE STATISTICS [Sales].[BigOrders] [NCI_BigOrders_OrderDate];
Ok, então nossos dados estão completamente carregados. Se verificarmos as estatísticas novamente e usarmos o sinalizador de rastreamento 2388 para exibir informações adicionais, veremos que a estatística é novamente marcada como Crescente:
DBCC TRACEON (2388);GO DBCC SHOW_STATISTICS('Vendas.BigOrders',[NCI_BigOrders_OrderDate]);
Estatística NCI OrderDate marcada como ASC com TF 2389 e modo de compatibilidade 130
Ok, então vamos consultar o dia 5 de junho novamente:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Vendas].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planeje com novo CE, sem linhas além do que está no histograma
Nossa estimativa é de 4.922. Não é bem o que era em nosso primeiro teste, mas definitivamente não 1. Agora vamos adicionar algumas linhas para 5 de junho e consultar novamente:
INSERIR [Sales].[BigOrders]( [OrderID],[CustomerID],[SalespersonPersonID],[PickedByPersonID],[ContactPersonID],[BackorderOrderID],[OrderDate],[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered ],[Comentários],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen])SELECT[OrderID] + 25400000,[CustomerID],[SalespersonIDID],[PickedByPersonID],[ContactPersonID],[ BackorderOrderID],'2016-06-05',[ExpectedDeliveryDate],[CustomerPurchaseOrderNumber],[IsUndersupplyBackordered],[Comments],[DeliveryInstructions],[InternalComments],[PickingCompletedWhen],[LastEditedBy],[LastEditedWhen] DE [Vendas] .[Pedidos];GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Planeje com novo CE, com mais de 70 mil linhas além do que está no histograma
A estimativa é a mesma. Então agora, e se desligarmos o sinalizador de rastreamento 2389?
DBCC TRACEOFF (2389, -1);GO DBCC FREEPROCCACHE;GO SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-05';
Plano com novo CE mas TF 2389 NÃO está habilitado, com 70K+ linhas além do que está no histograma
A estimativa mudou um pouco, para 4.930, mas mudou. Isso me diz que o sinalizador de rastreamento 2389 tem algum efeito na estimativa, mas quanto é desconhecido.
O Teste – Parte III
Executei um teste final, em que restaurei o banco de dados, configurei o modo de compatibilidade para 130, carreguei todos os dados novamente, atualizei as estatísticas várias vezes, mas NÃO ativei o sinalizador de rastreamento 2389. O código é o mesmo da Parte II, exceto pelo uso DBCC TRACEON para habilitar 2389. Quando consultei para 5 de junho, antes e depois de adicionar os dados, o número estimado de linhas era 4.920.
O que significa?
Para resumir, ao usar o modo de compatibilidade 110 ou inferior, o sinalizador de rastreamento 2389 funciona como sempre. Mas ao usar o modo de compatibilidade 120 ou superior e, portanto, o novo CE, as estimativas não o mesmo em relação ao antigo CE, e neste caso específico, não são tão diferentes usando ou não o sinalizador de rastreamento.
Então o que você deveria fazer? Teste, como sempre. Não encontrei nada documentado no MSDN que indique que o sinalizador de rastreamento 2389 não é compatível com o modo de compatibilidade 120 e superior, nem encontrei nada que documente uma alteração no comportamento. Acho muito interessante que as estimativas sejam diferentes (neste caso muito mais baixas) com o novo CE. Isso poderia ser um problema, mas há vários fatores em jogo quando se trata de estimativas, e essa foi uma consulta muito simples (uma tabela, um predicado). Nesse caso, a estimativa está muito distante (4.920 linhas versus 22.595 linhas para a data de 5 de junho).
Se eu executar novamente a consulta para uma data que tenha o mesmo número de linhas que é dentro do histograma, recebo um plano semelhante, mas é executado em paralelo:
SELECT CustomerID, OrderID, SalespersonPersonIDFROM [Sales].[BigOrders]WHERE [OrderDate] ='2016-06-02';
Planeje uma consulta que use uma data dentro do histograma (novo CE, sem TF)
A estimativa também é mais precisa (68.318). O plano não muda significativamente neste caso, mas o custo é obviamente maior. Em algum momento, dependendo do número de linhas que seriam retornadas, isso pode levar a uma verificação de tabela.
A melhor orientação neste momento, se você estiver executando 2014 ou superior e o modo de compatibilidade 120 ou superior, e tiver colunas principais em estatísticas crescentes, é testar. Se você achar que o novo Estimador de cardinalidade não fornece uma estimativa tão boa quanto o CE antigo, recomendo registrar um item do Connect para que a equipe do produto esteja ciente disso. Sempre há casos únicos e únicos, mas se muitos clientes (leia-se:VOCÊ) encontram consistentemente o mesmo comportamento – e não é o ideal – é importante informar a equipe de desenvolvimento sobre isso.
Este é outro item importante a ser considerado ao atualizar para 2014 ou 2016 – e um lembrete para não negligencie seus testes (e, a propósito, o Query Store seria extremamente útil aqui com 2016). Vamos lá amigos.