Usando estatísticas para melhorar o desempenho de consultas

O otimizador de consultas utiliza estatísticas para criar planos de consulta que melhoram o desempenho das consultas. Para a maioria das consultas, o otimizador já gera as estatísticas necessárias para um plano de consulta de alta qualidade; em alguns casos, você precisa criar estatísticas adicionais ou modificar o design da consulta para obter melhores resultados.

Este tópico discute os seguintes conceitos e diretrizes para o uso eficiente de estatísticas de otimização de consulta:

  • O que são estatísticas de otimização de consulta?

  • Usando as opções de estatísticas em todo o banco de dados

  • Determinando quando criar estatísticas

  • Determinando quando atualizar estatísticas

  • Criando consultas que usam estatísticas com eficiência

Para obter mais informações sobre o plano de consulta e como ele se relaciona com o desempenho de consultas, consulte Analisando uma consulta.

O que são estatísticas de otimização de consulta?

Estatísticas para otimização de consulta são objetos que contêm informações estatísticas sobre a distribuição de valores em uma ou mais colunas de uma tabela ou exibição indexada. O otimizador de consultas usa essas estatísticas para estimar a cardinalidade, ou número de linhas, no resultado de consulta. Essas estimativas de cardinalidade permitem que o otimizador crie um plano de consulta de alta qualidade. Por exemplo, o otimizador poderia usar as estimativas de cardinalidade para escolher o operador index seek em vez do operador index scan, o qual utiliza muitos recursos, e, assim, melhorar o desempenho das consultas.

Cada objeto de estatísticas é criado em uma lista de uma ou mais colunas de tabela e inclui um histograma que exibe a distribuição de valores na primeira coluna. Os objetos de estatísticas em várias colunas também armazenam informações estatísticas sobre a correlação de valores entre as colunas. Essas estatísticas de correlação, ou densidades, são derivadas do número de linhas distintas de valores de coluna. Para obter mais informações sobre objetos de estatísticas, consulte DBCC SHOW_STATISTICS (Transact-SQL).

Estatísticas filtradas

Estatísticas filtradas podem melhorar o desempenho de consultas selecionadas em subconjuntos bem definidos de dados. Estatísticas filtradas usam um predicado de filtro para selecionar o subconjunto de dados incluído nas estatísticas. As estatísticas filtradas bem projetadas podem aprimorar o plano de execução de consultas em comparação com as estatísticas de tabela completa. Para obter mais informações sobre o predicado de filtro, consulte CREATE STATISTICS (Transact-SQL). Para obter mais informações sobre quando criar estatísticas filtradas, consulte a seção Determinando quando criar estatísticas neste tópico. Para um estudo de caso, consulte a entrada do blog, Usando estatísticas filtradas com tabelas particionadas, no site do SQLCAT.

Usando as opções de estatísticas em todo o banco de dados

É importante entender o que as seguintes opções de estatísticas fazem e verificar se elas estão definidas corretamente:

  • AUTO_CREATE_STATISTICS

  • AUTO_UPDATE_STATISTICS

  • AUTO_UPDATE_STATISTICS_ASYNC

Usando a opção AUTO_CREATE_STATISTICS

Quando a opção de criação automática de estatísticas, AUTO_CREATE_STATISTICS, está ativada, o otimizador de consultas cria estatísticas em colunas individuais no predicado de consulta, conforme necessário, a fim de melhorar as estimativas de cardinalidade do plano de consulta. Essas estatísticas de coluna única são criadas em colunas que já não têm um histograma em um objeto de estatística existente.

Você pode usar a consulta a seguir para determinar se o otimizador de consultas criou estatísticas para uma coluna de predicado de consulta. Ela consulta as exibições de catálogo sys.stats e sys.stats_columns para retornar os nomes do objeto do banco de dados, da coluna e das estatísticas de todas as colunas que possuem estatísticas de coluna única. Quando o otimizador de consultas cria estatísticas em colunas únicas como resultado do uso da opção AUTO_CREATE_STATISTICS, os nomes das estatísticas iniciam com _WA.

USE AdventureWorks;
GO
SELECT OBJECT_NAME(s.object_id) AS object_name,
    COL_NAME(sc.object_id, sc.column_id) AS column_name,
    s.name AS statistics_name
FROM sys.stats AS s Join sys.stats_columns AS sc
    ON s.stats_id = sc.stats_id AND s.object_id = sc.object_id
WHERE s.name like '_WA%'
ORDER BY s.name;
GO

A opção AUTO_CREATE_STATISTICS não determina se são criadas estatísticas para índices. Essa opção também não gera estatísticas filtradas. Ela se aplica estritamente a estatísticas de coluna única para a tabela completa.

Usando a opção AUTO_UPDATE_STATISTICS

Quando a opção de atualização automática de estatísticas, AUTO_UPDATE_STATISTICS, está ativada, o otimizador de consultas determina quando as estatísticas podem estar desatualizadas e, em seguida, atualiza-as ao serem usadas por uma consulta. As estatísticas ficam desatualizadas depois que operações de inserção, atualização, exclusão ou mesclagem alteram a distribuição de dados na tabela ou na exibição indexada. O otimizador de consultas determina quando estatísticas podem estar desatualizadas, contando o número de modificações de dados desde a atualização das últimas estatísticas e comparando o número de modificações feitas em um limite. O limite se baseia no número de linhas na tabela ou na exibição indexada.

O otimizador de consultas procura estatísticas desatualizadas antes de compilar uma consulta e antes de executar um plano de consulta armazenado em cache. Antes de compilar uma consulta, o otimizador usa as colunas, as tabelas e as exibições indexadas no predicado de consulta para determinar quais estatísticas podem estar desatualizadas. Antes de executar um plano de consulta armazenado em cache, o Mecanismo de Banco de Dados verifica se o plano de consulta faz referência a estatísticas atualizadas.

A opção AUTO_UPDATE_STATISTICS se aplica a objetos de estatísticas criados para índices, colunas únicas em predicados de consulta e estatísticas criadas com a instrução CREATE STATISTICS. Essa opção também se aplica a estatísticas filtradas.

Definindo as opções AUTO_CREATE_STATISTICS e AUTO_UPDATE_STATISTICS como ON

A opção de criação automática de estatísticas, AUTO_CREATE_STATISTICS, e a opção de atualizações automática de estatísticas, AUTO_UPDATE_STATISTICS, são ativadas por padrão, o que é recomendável para a maioria dos bancos de dados de usuários. Você pode usar a seguinte instrução SELECT para exibir os valores atuais dessas opções para todos os bancos de dados de usuários:

SELECT name AS "Name", 
    is_auto_create_stats_on AS "Auto Create Stats",
    is_auto_update_stats_on AS "Auto Update Stats",
    is_read_only AS "Read Only" 
FROM sys.databases
WHERE database_ID > 4;
GO

O seguinte exemplo define AUTO_CREATE_STATISTICS e AUTO_UPDATE_STATISTICS como ON para o banco de dados AdventureWorks:

USE AdventureWorks;
GO
ALTER DATABASE AdventureWorks
    SET AUTO_CREATE_STATISTICS ON;
ALTER DATABASE AdventureWorks
    SET AUTO_UPDATE_STATISTICS ON;
GO

Para obter mais informações sobre como definir essas opções de estatísticas, consulte Opções ALTER DATABASE SET (Transact-SQL).

Desabilitando e reabilitando AUTO_UPDATE_STATISTICS para algumas estatísticas

Quando AUTO_UPDATE_STATISTICS estiver ativada, você poderá substituir a forma de atualização das estatísticas em todo o banco de dados e desativar atualizações automáticas de estatísticas para uma tabela, índice ou coluna em particular, conforme solicitado pelo seu aplicativo. Quando AUTO_UPDATE_STATISTICS estiver ativada, você poderá desabilitar e reabilitar atualizações automáticas de estatísticas para uma tabela, um índice ou uma coluna das seguintes formas:

  • Use o procedimento armazenado do sistema sp_autostats. Isso pode desabilitar ou reabilitar atualizações de estatísticas para uma tabela ou um índice.

  • Especifique a opção NORECOMPUTE com a instrução UPDATE STATISTICS. Para reabilitar atualizações de estatísticas execute novamente UPDATE STATISTICS sem a opção NORECOMPUTE.

  • Especifique a opção NORECOMPUTE com a instrução CREATE STATISTICS. Para reabilitar atualizações de estatísticas, remova as estatísticas com DROP STATISTICS e execute CREATE STATISTICS sem a opção NORECOMPUTE.

  • Especifique a opção STATISTICS_NORECOMPUTE com a instrução CREATE INDEX. Para reabilitar atualizações de estatísticas, você pode executar ALTER INDEX com STATISTICS_NORECOMPUTE = OFF.

Quando AUTO_UPDATE_STATISTICS estiver desativada, você não poderá definir atualizações automáticas como ON para uma tabela, um índice ou uma coluna em particular. A reabilitação de atualizações automáticas de estatísticas restaura o comportamento especificado pela opção AUTO_UPDATE_STATISTICS. Se a opção AUTO_UPDATE_STATISTICS estiver desativada, as atualizações de estatísticas não ocorrerão.

Quando usar atualizações de estatísticas síncronas ou assíncronas

Atualizações de estatísticas podem ser síncronas (o padrão) ou assíncronas. Com atualizações de estatísticas síncronas, as consultas são sempre compiladas e executadas com estatísticas atualizadas; Quando as estatísticas estão desatualizadas, o otimizador de consultas espera por estatísticas atualizadas antes de compilar e executar a consulta. Com atualizações de estatísticas assíncronas, as consultas são compiladas com estatísticas existentes mesmo se as estatísticas estiverem desatualizas; O otimizador de consultas poderia escolher um plano de consulta com qualidade inferior se as estatísticas estivessem desatualizadas na compilação da consulta. As consultas compiladas após o término das atualizações assíncronas serão beneficiadas por usarem estatísticas atualizadas.

A opção de atualização de estatísticas assíncronas em todo o banco de dados, AUTO_UPDATE_STATISTICS_ASYNC, determina se o otimizador de consultas usa atualizações de estatísticas síncronas ou assíncronas. Por padrão, a opção de atualização de estatísticas assíncrona é desativada e o otimizador de consultas atualiza estatísticas de forma síncrona. A opção AUTO_UPDATE_STATISTICS_ASYNC se aplica a objetos de estatísticas criados para índices, colunas únicas em predicados de consulta e estatísticas criadas com a instrução CREATE STATISTICS.

Você pode usar o comando seguinte para exibir a opção de atualização automática assíncrona para todos os bancos de dados:

SELECT name AS "Name", 
    is_auto_update_stats_async_on AS "Asynchronous Update" 
FROM sys.databases;
GO

Convém usar estatísticas síncronas para o seguinte cenário:

  • Você executa operações que alteram a distribuição de dados, como truncar uma tabela ou executar uma atualização em massa de um percentual grande das linhas. Se você não atualizar as estatísticas depois de concluir a operação, o uso de estatísticas síncronas irá garantir que as estatísticas sejam atualizadas antes da execução de consultas nos dados alterados.

Convém usar estatísticas assíncronas para obter tempos de resposta de consulta mais previsíveis para os seguintes cenários:

  • Seu aplicativo freqüentemente executa a mesma consulta, consultas semelhantes ou planos de consulta armazenados em cache semelhantes. Seus tempos de resposta de consulta poderiam ser mais previsíveis com atualizações de estatísticas assíncronas do que com atualizações de estatísticas síncronas porque o otimizador pode executar consultas de entrada sem esperar por estatísticas atualizadas. Isso evita a demora de algumas consultas, e outras não. Para obter mais informações sobre como localizar consultas semelhantes, consulte Localizando e ajustando consultas semelhantes usando consulta e hashes de plano de consulta.

  • Seu aplicativo excedeu o tempo limite de solicitações do cliente pelo fato de uma ou mais consultas estarem aguardando a atualização de estatísticas. Em alguns casos, a espera por estatísticas síncronas pode gerar falhas em aplicativos com tempos limites curtos.

Determinando quando criar estatísticas

O otimizador de consultas já cria estatísticas das seguintes maneiras:

  1. O otimizador de consultas cria estatísticas para índices em tabelas ou exibições quando o índice é criado. Essas estatísticas são criadas nas colunas de chave do índice. Se o índice for um índice filtrado, o otimizador criará estatísticas filtradas no mesmo subconjunto de linhas especificado para o índice filtrado. Para obter mais informações sobre índices filtrados, consulte Diretrizes de criação de índice filtrado e CREATE INDEX (Transact-SQL).

  2. O otimizador de consultas cria estatísticas para colunas únicas em predicados de consulta quando AUTO_CREATE_STATISTICS estiver ativada.

Para a maioria das consultas, esses dois métodos para criar estatísticas asseguram um plano de consulta de alta qualidade; em alguns casos, você pode aprimorar os planos de consulta criando estatísticas adicionais com a instrução CREATE STATISTICS. Essas estatísticas adicionais podem capturar correlações estatísticas que o otimizador de consulta não captura ao criar estatísticas para índices ou colunas. Seu aplicativo pode ter correlações estatísticas adicionais nos dados de tabela que, se calculadas em um objeto de estatísticas, poderia fazer com que o otimizador melhorasse os planos de consulta. Por exemplo, estatísticas filtradas em um subconjunto de linhas de dados ou estatísticas multicolunas em colunas de predicado de consulta poderiam melhorar o plano de consulta.

Ao criar estatísticas com a instrução CREATE STATISTICS, recomendamos manter a opção AUTO_CREATE_STATISTICS ativada de forma que o otimizador de consultas continue criando estatísticas da coluna única para colunas de predicado de consulta. Para obter mais informações sobre predicados de consulta, consulte Critério de pesquisa (Transact-SQL).

Convém criar estatísticas com a instrução CREATE STATISTICS quando qualquer uma destas situações ocorrer:

  • O Orientador de Otimização do Mecanismo de Banco de Dados sugere criar estatísticas.

  • O predicado de consulta contém várias colunas correlacionadas que já não estão no mesmo índice.

  • A consulta faz a seleção em um subconjunto de dados.

  • Há estatísticas ausentes na consulta.

O Orientador de Otimização do Mecanismo de Banco de Dados sugere criar estatísticas

O Orientador de Otimização do Mecanismo de Banco de Dados é uma ferramenta que analisa os efeitos do desempenho de cargas de trabalho em uma ou mais bancos de dados. Ele faz recomendações para melhorar o desempenho (como sugerir a criação de índices) e sugere o uso de CREATE STATISTICS para criar estatísticas de otimização de consulta. Você deveria seguir essa recomendação. Para obter mais informações sobre o Orientador de Otimização do Mecanismo de Banco de Dados, consulte Ajustando o design do banco de dados físico

O predicado de consulta contém várias colunas correlacionadas

Quando um predicado de consulta contém várias colunas que têm relações umas com as outras e dependências, as estatísticas nas várias colunas poderiam melhorar o plano de consulta. Estatísticas em várias colunas contêm estatísticas de correlação entre colunas, chamadas densidades, que não estão disponíveis em estatísticas de coluna única. As densidades podem melhorar as estimativas de cardinalidade quando resultados de consulta dependerem de relações de dados entre várias colunas.

Se as colunas já estiverem no mesmo índice, o objeto de estatísticas multicolunas já existirá e não será necessário criá-lo manualmente. Se as colunas não estiverem no mesmo índice, você poderá criar estatísticas multicolunas criando um índice nas colunas ou usando a instrução CREATE STATISTICS. A manutenção de um índice exige mais recursos do sistema do que a de um objeto de estatísticas. Se o aplicativo não exigir o índice multicolunas, você poderá poupar os recursos do sistema criando o objeto de estatísticas sem criar o índice.

Ao criar estatísticas multicolunas, a ordem das colunas na definição do objeto de estatísticas afeta a efetividade de densidades para calcular estimativas de cardinalidade. O objeto de estatísticas armazena densidades para cada prefixo de colunas de chave na definição do objeto. Para obter mais informações sobre densidades, consulte DBCC SHOW_STATISTICS (Transact-SQL).

Para criar densidades úteis para estimativas de cardinalidade, as colunas no predicado de consulta devem corresponder a um dos prefixos de colunas na definição do objeto de estatísticas. O exemplo a seguir cria um objeto de estatísticas multicolunas nas colunas LastName, MiddleName e FirstName.

USE AdventureWorks;
GO
IF EXISTS (SELECT name FROM sys.stats
    WHERE name = 'LastFirst'
    AND object_ID = OBJECT_ID ('Person.Contact'))
DROP STATISTICS Person.Contact.LastFirst;
GO
CREATE STATISTICS LastFirst ON Person.Contact (LastName, MiddleName, FirstName);
GO

Neste exemplo, o objeto de estatísticas LastFirst possui densidades para os seguintes prefixos de coluna: (LastName), (LastName, MiddleName) e (LastName, MiddleName, FirstName). A densidade não está disponível para (LastName, FirstName). Se a consulta usar LastName e FirstName sem usar MiddleName, a densidade não estará disponível para estimativas de cardinalidade.

A consulta faz seleções em um subconjunto de dados

Quando o otimizador de consultas cria estatísticas para colunas e índices, ele cria as estatísticas para obter os valores em todas as linhas. Quando as consultas fazem seleções em um subconjunto de linhas, e esse subconjunto tem uma distribuição de dados exclusiva, as estatísticas filtradas podem aprimorar os planos de consulta. É possível criar estatísticas filtradas usando a instrução CREATE STATISTICS com a cláusula WHERE para definir a expressão de predicado de filtro.

Por exemplo, usando o AdventureWorks, cada produto da tabela Production.Product pertence a uma das quatro categorias na tabela Production.ProductCategory: Bicicletas, Componentes, Vestuário e Acessórios. Cada categoria possui uma distribuição diferente de dados de acordo com o peso: as bicicletas pesam de 13,77 a 30, os componentes pesam de 2,12 a 1.050 com alguns valores NULL, o peso das roupas é NULL e o peso dos acessórios também é NULL.

Usando Bicicletas como um exemplo, as estatísticas filtradas em todos os pesos de bicicleta fornecerão estatísticas mais precisas ao otimizador de consultas e podem melhorar a qualidade do plano de consulta comparadas com as estatísticas de tabela completa ou estatísticas inexistentes na coluna Weight. A coluna de peso da bicicleta é uma boa candidata para estatísticas filtradas, mas não necessariamente para um índice filtrado se o número de pesquisas de peso for relativamente pequeno. O ganho de desempenho que um índice filtrado fornece às pesquisas pode não compensar a manutenção adicional e os custos de armazenamento exigidos para adicionar um índice filtrado ao banco de dados.

A instrução a seguir cria as estatísticas BikeWeights filtradas em todas as subcategorias de Bicicletas. A expressão de predicado filtrada define bicicletas enumerando todas as subcategorias com a comparação Production.ProductSubcategoryID IN (1,2,3). O predicado não pode usar o nome de categoria Bicicletas porque ele está armazenado na tabela Production.ProductCategory e todas as colunas na expressão de filtro devem estar na mesma tabela.

USE AdventureWorks;
GO
IF EXISTS ( SELECT name FROM sys.stats
    WHERE name = 'BikeWeights'
    AND object_ID = OBJECT_ID ('Production.Product'))
DROP STATISTICS Production.Product.BikeWeights;
GO
CREATE STATISTICS BikeWeights
    ON Production.Product (Weight)
WHERE ProductSubcategoryID IN (1,2,3);
GO

O otimizador de consultas pode usar as estatísticas filtradas BikeWeights para aprimorar o plano da consulta a seguir, que seleciona todas as bicicletas que pesam mais de 25.

SELECT P.Weight AS Weight, S.Name AS BikeName
FROM Production.Product AS P
    JOIN Production.ProductSubcategory AS S 
    ON P.ProductSubcategoryID = S.ProductSubcategoryID
WHERE P.ProductSubcategoryID IN (1,2,3) AND P.Weight > 25
ORDER BY P.Weight;
GO

Há estatísticas ausentes na consulta

Se um erro ou outro evento impedir que o otimizador de consultas crie estatísticas, o otimizador criará o plano de consulta sem usar estatísticas. O otimizador marca as estatísticas como ausentes e tenta gerar as estatísticas novamente na próxima execução da consulta.

As estatísticas ausentes são indicadas como avisos (nome de tabela em texto vermelho) quando o plano de execução de uma consulta é exibido graficamente usando o SQL Server Management Studio. Para obter mais informações, consulte Exibindo planos de execução gráfica (SQL Server Management Studio). Além disso, o monitoramento da classe de evento Missing Column Statistics usando SQL Server Profiler indica quando há estatísticas ausentes. Para obter mais informações, consulte Categoria de eventos de erros e de avisos (Mecanismo de Banco de Dados).

Se houver estatísticas ausentes, execute as seguintes etapas:

  • Verifique se AUTO_CREATE_STATISTICS e AUTO_UPDATE_STATISTICS estão ativadas.

  • Verifique se o banco de dados não é somente leitura. Se o banco de dados for somente leitura, o otimizador de consultas não poderá salvar estatísticas.

  • Crie as estatísticas ausentes com a instrução CREATE STATISTICS.

Determinando quando atualizar estatísticas

O otimizador de consultas determina quando as estatísticas podem estar desatualizadas e as atualiza caso sejam necessárias para um plano de consulta. Em alguns casos, você pode melhorar o plano de consulta e, portanto, o desempenho das consultas atualizando estatísticas regularmente. Esse procedimento costuma ser mais eficaz do que ativar a opção AUTO_UPDATE_STATISTICS. Você pode atualizar estatísticas com a instrução UPDATE STATISTICS ou o procedimento armazenado sp_updatestats.

A atualização de estatísticas assegura que as consultas sejam compiladas com estatísticas atualizadas. Porém, a atualização de estatísticas faz com que as consultas sejam recompiladas. Recomendamos não atualizar estatísticas com muita freqüência porque existe uma compensação de desempenho entre a melhoria dos planos de consulta e o tempo necessário à recompilação das consultas. As compensações específicas dependem do seu aplicativo.

Quando você atualizar estatísticas com UPDATE STATISTICS ou sp_updatestats, recomendamos manter a opção AUTO_UPDATE_STATISTICS ativada de forma que o otimizador de consultas continue a atualizar estatísticas periodicamente. Para obter mais informações sobre como atualizar estatísticas em uma coluna, um índice, uma tabela ou uma exibição indexada, consulte UPDATE STATISTICS (Transact-SQL). Para obter informações sobre como atualizar estatísticas de todas as tabelas definidas pelo usuário e internas no banco de dados, consulte o procedimento armazenado sp_updatestats (Transact-SQL). Por exemplo, o comando a seguir chama sp_updatestats para atualizar todas as estatísticas do banco de dados.

EXEC sp_updatestats

Para determinar quando as estatísticas foram atualizadas pela última vez, use a função STATS_DATE.

Convém atualizar estatísticas nas seguintes condições:

  • Os tempos de execução de consulta estão lentos.

  • As operações de inserção ocorrem em colunas de chaves crescentes ou decrescentes.

  • Após operações de manutenção.

Os tempos de execução de consulta estão lentos

Se os tempos de resposta de consulta estiverem lentos ou imprevisíveis, certifique-se de que as consultas tenham estatísticas atualizadas antes de executar as etapas adicionais de solução de problemas. Para obter mais informações sobre como solucionar problemas de consultas lentas, consulte Lista de verificação para análise de consultas lentas.

As operações de inserção ocorrem em colunas de chaves crescentes ou decrescentes

Estatísticas em colunas de chaves crescentes ou decrescentes, como colunas IDENTITY ou colunas de carimbo de data/hora em tempo real, podem exigir atualizações de estatísticas mais freqüentes do que as executadas pelo otimizador de consultas. As operações de inserção adicionam novos valores às colunas crescentes ou decrescentes. O número de linhas adicionado pode ser muito pequeno para disparar uma atualização de estatísticas. Se as estatísticas não forem atualizadas e as consultas fizerem seleções em linhas recentemente adicionadas, as estatísticas atuais não terão estimativas de cardinalidade para obter esses novos valores. Isso pode resultar em estimativas de cardinalidade imprecisas e lentidão no desempenho de consulta.

Por exemplo, uma consulta que faz seleções em ordens de venda com as datas mais recentes terá estimativas de cardinalidade imprecisas se as estatísticas não forem atualizadas para incluir estimativas de cardinalidade dessas ordens de venda.

Após operações de manutenção

Convém atualizar estatísticas depois de executar procedimentos de manutenção que alteram a distribuição de dados, como truncar uma tabela ou executar uma inserção em massa de um percentual grande das linhas. Esse procedimento pode evitar atrasos futuros no processamento de consultas enquanto elas esperam por atualizações automáticas de estatísticas.

Operações como reconstrução, desfragmentação ou reorganização de um índice não alteram a distribuição dos dados. Portanto, você não precisa atualizar estatísticas depois de executar as operações ALTER INDEX REBUILD, DBCC REINDEX, DBCC INDEXDEFRAG ou ALTER INDEX REORGANIZE. O otimizador de consultas atualiza estatísticas quando você reconstrói um índice em uma tabela ou exibição com ALTER INDEX REBUILD ou DBCC DBREINDEX; porém, essa atualização de estatísticas é um subproduto da recriação do índice. O otimizador de consultas não atualiza estatísticas depois de operações DBCC INDEXDEFRAG ou ALTER INDEX REORGANIZE.

Criando consultas que usam estatísticas com eficiência

Algumas implementações de consulta, como variáveis locais e expressões complexas no predicado de consulta, podem gerar planos de consulta de qualidade inferior. O cumprimento das diretrizes de design de consulta para o uso eficiente de estatísticas pode ajudar a evitar esse problema. Para obter mais informações sobre predicados de consulta, consulte Critério de pesquisa (Transact-SQL).

Você pode melhorar planos de consulta aplicando diretrizes de design de consulta que usam estatísticas de modo eficiente para aprimorar estimativas de cardinalidade para expressões, variáveis e funções usadas em predicados de consulta. Quando o otimizador de consulta não souber o valor de uma expressão, variável ou função, ele não saberá qual o valor a ser pesquisado no histograma e, portanto, não poderá recuperar a melhor estimativa de cardinalidade do histograma. Em vez disso, o otimizador de consultas baseia a estimativa de cardinalidade no número médio de linhas por valor distinto para todas as linhas de amostra no histograma. Isso gera estimativas de cardinalidade de qualidade inferior e prejudica o desempenho das consultas.

As diretrizes a seguir descrevem como escrever consultas para melhorar planos de consulta por meio do aprimoramento das estimativas de cardinalidade.

Melhorando estimativas de cardinalidade para expressões

Para melhorar estimativas de cardinalidade para expressões, siga estas diretrizes:

  • Sempre que possível, simplifique expressões com constantes. O otimizador de consultas não avalia todas as funções e expressões que contêm constantes antes de determinar as estimativas de cardinalidade. Por exemplo, simplifique a expressão ABS (-100) to 100.

  • Se a expressão usar muitas variáveis, convém criar uma coluna computada para a expressão e criar estatísticas ou um índice na coluna computada. Por exemplo, o predicado de consulta WHERE PRICE + Tax > 100 pode ter uma estimativa de cardinalidade melhor se você criar uma coluna computada para a expressão Price + Tax.

Melhorando estimativas de cardinalidade para variáveis e funções

Para melhorar as estimativas de cardinalidade para variáveis e funções, siga estas diretrizes:

  • Se o predicado de consulta usar uma variável local, convém reescrever a consulta para usar um parâmetro em vez de uma variável local. O valor de uma variável local não é conhecido quando o otimizador de consulta cria o plano de execução de consulta. Quando uma consulta usar um parâmetro, o otimizador de consultas usará a estimativa de cardinalidade para obter o primeiro valor de parâmetro real transmitido ao procedimento armazenado.

  • Convém usar uma tabela padrão ou tabela temporária para armazenar os resultados de funções com valor de tabela de várias instruções. O otimizador de consultas não cria estatísticas para funções com valor de tabela de várias instruções. Com essa abordagem o otimizador pode criar estatísticas nas colunas de tabela e usá-las para criar um plano de consulta melhor. Para obter mais informações sobre as funções com valor de tabela de várias instruções, consulte Tipos de funções.

  • Convém usar uma tabela padrão ou tabela temporária como uma substituição para variáveis de tabela. O otimizador de consultas não cria estatísticas para variáveis de tabela. Com essa abordagem o otimizador pode criar estatísticas nas colunas de tabela e usá-las para criar um plano de consulta melhor. Há compensações ao optar pelo uso de uma tabela temporária ou de uma variável de tabela; as variáveis de tabela usadas em procedimentos armazenados causam menos recompilações do procedimento armazenado que as tabelas temporárias. Dependendo do aplicativo, o uso de uma tabela temporária em vez de uma variável de tabela poderá não otimizar o desempenho.

  • Se um procedimento armazenado contiver uma consulta que usa um parâmetro transmitido, evite alterar o valor de parâmetro dentro do procedimento armazenado antes de usá-lo na consulta. As estimativas de cardinalidade para a consulta baseiam-se no valor de parâmetro transmitido, e não no valor atualizado. Para evitar alterar o valor do parâmetro, reescreva a consulta para usar dois procedimentos armazenados.

    Por exemplo, o procedimento armazenado Sales.GetRecentSales a seguir altera o valor do parâmetro @date quando @date is NULL.

    USE AdventureWorks;
    GO
    IF OBJECT_ID ( 'Sales.GetRecentSales', 'P') IS NOT NULL
        DROP PROCEDURE Sales.GetRecentSales;
    GO
    CREATE PROCEDURE Sales.GetRecentSales (@date datetime)
    AS BEGIN
        IF @date is NULL
            SET @date = DATEADD(MONTH, -3, (SELECT MAX(ORDERDATE) FROM Sales.SalesOrderHeader))
        SELECT * FROM Sales.SalesOrderHeader h, Sales.SalesOrderDetail d
        WHERE h.SalesOrderID = d.SalesOrderID
        AND h.OrderDate > @date
    END
    GO
    

    Se a primeira chamada ao procedimento armazenado Sales.GetRecentSales transmitir um NULL para o parâmetro @date, o otimizador de consultas compilará o procedimento armazenado com a estimativa de cardinalidade para @date = NULL embora o predicado de consulta não seja chamado com @date = NULL. Essa estimativa de cardinalidade pode ser relativamente diferente que o número de linhas no resultado de consulta. Isso poderia levar o otimizador de consultas a escolher um plano de consulta de qualidade inferior. Para evitar isso, você pode reescrever o procedimento armazenado em dois procedimentos da seguinte maneira:

    USE AdventureWorks;
    GO
    IF OBJECT_ID ( 'Sales.GetNullRecentSales', 'P') IS NOT NULL
        DROP PROCEDURE Sales.GetNullRecentSales;
    GO
    CREATE PROCEDURE Sales.GetNullRecentSales (@date datetime)
    AS BEGIN
        IF @date is NULL
            SET @date = DATEADD(MONTH, -3, (SELECT MAX(ORDERDATE) FROM Sales.SalesOrderHeader))
        EXEC Sales.GetNonNullRecentSales @date;
    END
    GO
    IF OBJECT_ID ( 'Sales.GetNonNullRecentSales', 'P') IS NOT NULL
        DROP PROCEDURE Sales.GetNonNullRecentSales;
    GO
    CREATE PROCEDURE Sales.GetNonNullRecentSales (@date datetime)
    AS BEGIN
        SELECT * FROM Sales.SalesOrderHeader h, Sales.SalesOrderDetail d
        WHERE h.SalesOrderID = d.SalesOrderID
        AND h.OrderDate > @date
    END
    GO
    

Melhorando estimativas de cardinalidade com dicas de consulta

Para melhorar estimativas de cardinalidade para variáveis locais, você pode usar as dicas de consulta OPTIMIZE FOR ou OPTIMIZE FOR UNKNOWN com RECOMPILE. Para obter mais informações, consulte dicas de consulta (Transact-SQL).

Para alguns aplicativos, a recompilação da consulta toda vez que ela é executada pode demorar em excesso. Uma dica de consulta OPTIMIZER FOR poderá ajudar até mesmo se você não usar a opção RECOMPILE. Por exemplo, você poderia acrescentar uma opção OPTIMIZER FOR ao procedimento armazenado Sales.GetRecentSales para especificar uma data específica. O exemplo a seguir acrescenta a opção OPTIMIZE FOR ao procedimento Sales.GetRecentSales.

USE AdventureWorks;
GO
IF OBJECT_ID ( 'Sales.GetRecentSales', 'P') IS NOT NULL
    DROP PROCEDURE Sales.GetRecentSales;
GO
CREATE PROCEDURE Sales.GetRecentSales (@date datetime)
AS BEGIN
    IF @date is NULL
        SET @date = DATEADD(MONTH, -3, (SELECT MAX(ORDERDATE) FROM Sales.SalesOrderHeader))
    SELECT * FROM Sales.SalesOrderHeader h, Sales.SalesOrderDetail d
    WHERE h.SalesOrderID = d.SalesOrderID
    AND h.OrderDate > @date
    OPTION ( OPTIMIZE FOR ( @date = '2004-05-01 00:00:00.000'))
END;
GO

Melhorando estimativas de cardinalidade com guias de plano

Para alguns aplicativos, é possível que as diretrizes de design de consulta não se apliquem porque você não pode alterar a consulta; ou o uso da dica RECOMPILE pode ser causar um excesso de recompilações. Você pode usar guias de plano para especificar outras dicas, como USE PLAN, a fim de controlar o comportamento da consulta enquanto investiga alterações do aplicativo com o fornecedor do aplicativo. Para obter mais informações sobre guias de plano, consulte Otimizando consultas em aplicações implantadas com guias de plano.