O SQL Server existe há mais de 30 anos e trabalho com o SQL Server há quase tanto tempo. Kalen aborda as varreduras na Parte Um de SQL Server Internals:Problematic Operators.
Eu vi muitas mudanças ao longo dos anos (e décadas!) e versões deste produto incrível. Nestas postagens, compartilharei com você como vejo alguns dos recursos ou aspectos do SQL Server, às vezes com um pouco de perspectiva histórica.
Ajustar suas consultas do SQL Server é uma das melhores coisas que você pode fazer para melhorar o desempenho e a otimização do diagnóstico do SQL Server. Mas o ajuste é um assunto enorme! Saber exatamente como ajustar da melhor maneira possível requer não apenas um conhecimento profundo de seus dados e sua carga de trabalho, mas também conhecimento de como o SQL Server realmente faz suas escolhas de execução de planos. Então, o que você pode fazer se não for um especialista em SQL Server Internals? Uma coisa que você pode fazer é confiar em pessoas que são especialistas, bem como em ferramentas escritas por especialistas. Ferramentas como o Quest Spotlight Cloud Tuning Pack podem oferecer ótimas sugestões para começar a melhorar o desempenho das consultas. Obviamente, nenhuma ferramenta externa conhece seus dados e todos os detalhes de todas as suas cargas de trabalho, portanto, é sempre recomendável testar minuciosamente qualquer sugestão que você decida implementar.
Nestas postagens sobre operadores problemáticos, presumirei que você tenha algum conhecimento básico das estruturas de índice do SQL Server. Aqui estão algumas informações que serão úteis:
- Uma tabela sem um índice clusterizado é chamada de heap e não tem ordenação. Não há primeira ou última linha. Um heap é apenas um monte de linhas em nenhuma ordem específica.
- O nível folha de um índice clusterizado é a própria tabela. (Não é uma cópia da tabela, é a tabela.) As linhas do índice são ordenadas logicamente por qualquer coluna que foi definida para ser a chave do índice clusterizado.
- O nível folha de um índice não clusterizado contém uma linha de índice para cada linha da tabela. As linhas contêm as colunas de chave não clusterizadas e são ordenadas logicamente na ordem em que as chaves são especificadas. Além das colunas de chave, as linhas de índice não clusterizadas contêm um 'indicador' que aponta para a linha referenciada na tabela. O marcador pode estar em uma das duas formas:
- Se a tabela tiver um índice clusterizado, o marcador será a chave do índice clusterizado. (Se a chave de índice clusterizado fizer parte da chave de índice não clusterizada, ela não será duplicada.)
- Se a tabela for um heap, o marcador será um ID de linha ou RID, que especifica o local físico da linha. O local geralmente é especificado como FileNum:PageNum:RowNum .
As próprias ferramentas do SQL Server fornecem várias maneiras de visualizar o plano de execução da consulta que o otimizador decidiu usar para uma consulta específica. Com a adição do Quest Spotlight Tuning Pack, você pode obter ainda mais informações sobre seus planos.
O código a seguir cria cópias de duas tabelas no AdventureWorks banco de dados (estou usando o AdventureWorks2016 , mas você pode usar outra versão).
USE AdventureWorks2016;
GO
DROP TABLE IF EXISTS SalesHeader;
GO
SELECT *
INTO SalesHeader
FROM Sales.SalesOrderHeader;
GO
DROP TABLE IF EXISTS SalesDetail;
GO
SELECT * INTO SalesDetail
FROM Sales.SalesOrderDetail;
GO
Agora execute uma consulta que una as duas tabelas, após ativar “Incluir Plano de Execução Real”
SELECT h.SalesOrderID, OrderDate, ProductID, UnitPrice, OrderQty
FROM SalesHeader h JOIN SalesDetail d
ON h.SalesOrderID = d.SalesOrderID
WHERE SalesOrderDetailID < 100;
GO
O Quest Spotlight Tuning Pack reportará um problema com a consulta, então você pode clicar em “View Analysis” e escolher a opção “Execution Plan”. Você deve ver o seguinte:
Compreendendo as varreduras de tabela
Primeiro, quero arriscar e dizer que não há operadora de plano que seja sempre ruim! Por que o otimizador o adicionaria ao seu plano de consulta se fosse ruim? Pode indicar que há espaço para melhorias em seus dados ou estruturas de índice, mas em si não é ruim.
No exemplo acima, o Tuning Pack parece estar destacando as varreduras da tabela, indicando que elas podem ser problemáticas. Mas nem sempre é verdade que as varreduras de tabela são problemáticas. Uma situação muito pior seria usar uma busca de índice não clusterizado para uma consulta que acessa todas as linhas da tabela. Para essa consulta específica, concordo que a verificação pode não ser uma boa coisa porque estamos interessados apenas em algumas linhas no SalesDetail tabela (99 de 121.317 linhas, ou menos de um décimo de um por cento.)
Assim, podemos examinar as sugestões no painel Análise para construir índices. A sugestão para o SalesDetail table é construir um índice não clusterizado no SalesOrderID column (a coluna na cláusula JOIN) e INCLUDE todas as outras colunas na tabela que é retornada pela consulta. A sugestão para o SalesHeader table é um índice não clusterizado no SalesOrderDetailId coluna, que é a coluna na cláusula WHERE, e INCLUIR a OrderDate column, que é a única outra coluna retornada desta tabela.
E se nossa consulta fosse um pouco diferente? E se eu tivesse executado esta consulta usando SELECT * em vez de uma lista de colunas específica. Se você tentar e observar as recomendações, ele sugere usar o INCLUDE para cada coluna da tabela, exceto a coluna de chave única. Embora esse índice possa fazer com que essa consulta específica seja executada um pouco mais rápido, pode acabar retardando outras consultas, em particular suas consultas UPDATE. Esse índice basicamente é apenas uma cópia da tabela, porque o nível folha do índice conterá todas as colunas da tabela. Se você vir recomendações como essa, sugerindo um índice que inclua todas as colunas da tabela, definitivamente recomendo recuar um pouco e não criá-lo cegamente.
O ajuste de consulta para o diagnóstico do SQL Server envolve não apenas o gerenciamento de índices, mas também o gerenciamento das próprias consultas. Para essa consulta específica, talvez seja melhor reescrever a consulta para NÃO usar SELECT * para retornar todas as linhas da tabela. Retornar apenas um pequeno subconjunto das colunas pode ser suficiente e, em seguida, um índice muito mais estreito seria suficiente, como no primeiro exemplo.
Algum desses índices seria realmente um bom índice para criar? O índice mais restrito será menor em geral e será menos afetado por atualizações nos dados. Um índice em todas as colunas é como uma segunda cópia da tabela, classificada em uma ordem diferente da própria tabela. Existem situações em que ter uma “segunda cópia” da tabela em uma ordem diferente pode ser útil, mas haverá muita sobrecarga para operações de modificação de dados. A única maneira de saber com certeza é testar as recomendações em um sistema de teste com uma carga de trabalho representativa. Só você conhece seus dados e suas consultas, então experimente e veja!
Compreendendo as verificações de índice
Como mencionei acima, as varreduras de tabela nem sempre são uma coisa ruim. Mas e as verificações de índice? Como um nível folha de índice clusterizado é a própria tabela, uma verificação de índice clusterizado é o mesmo que uma verificação de tabela! se uma verificação de tabela for ruim, uma verificação de índice clusterizado será igualmente ruim. Mas nem sempre é ruim. Novamente, você precisa testá-lo em seu sistema.
As recomendações do SQL Server Engine que o Quest Spotlight Tuning Pack mostra nunca sugerem um índice clusterizado. ele pode sugerir um não clusterizado que inclui todas as colunas da tabela (como mencionado anteriormente), que é apenas uma duplicata da tabela. Descobrir a melhor coluna ou colunas para o seu índice clusterizado é um grande tópico em si, então não vou entrar nisso aqui.
O que é uma busca? Uma operação de busca em um plano significa que o SQL Server está usando os dados ordenados na árvore de índice para localizar uma linha, um conjunto de linhas ou o ponto inicial e/ou final em um intervalo de linhas. Em geral, usar uma busca de índice não clusterizado é uma operação perfeitamente razoável se você estiver retornando apenas uma porcentagem muito pequena de linhas de uma tabela. Mas uma busca não é uma boa escolha para uma consulta que está retornando MUITAS linhas de uma tabela. Quanto é MUITO? Não há uma resposta simples, mas se sua consulta estiver retornando mais do que alguns por cento das linhas, certifique-se de testar as sugestões de índice completamente. Às vezes, uma varredura de tabela, ou varredura de índice clusterizado, é melhor do que uma busca de índice. (Para um exemplo, veja minha postagem no blog aqui).
Ferramentas como o Pacote de ajuste do Quest Spotlight pode fornecer ótimas sugestões para começar sua jornada de ajuste com diagnósticos do SQL Server, mas quanto mais você souber sobre como os índices do SQL Server e o otimizador do SQL Server funcionam, melhor poderá avaliar essas sugestões para suas consultas e seus dados, e possivelmente até mesmo apresentar suas próprias sugestões.
Nas próximas postagens desta série, falarei sobre outros operadores problemáticos que podem aparecer em seus planos de consulta, então volte em breve!