Esse artigo faz parte da revistaSQL Magazine edição 65. Clique aqui para ler todos os artigos desta edição

eterminado lugar pode ser considerado para muitos uma arte, isso porque sempre existem vários caminhos que levam ao mesmo destino. Executar uma tarefa da forma mais eficiente possível requer que o caminho percorrido seja o melhor dentre as centenas de variáveis que podem influenciar na escolha do melhor percurso.

No SQL Server o responsável por calcular a maneira mais eficiente de acesso aos dados é chamado de Query Processor, ele é dividido em duas partes, o Query Optimizer e o Query Execution Engine. Veremos neste artigo como o Query Optimizer funciona e quais os passos necessários para execução de um comando T-SQL.

Entender como funciona e como interpretar o trabalho do Query Optimizer é uma das melhores maneiras de aprimorar seus conhecimentos em SQL Server. Esse conhecimento será de grande valor quando você precisar fazer algum trabalho de tunning em banco de dados.

Preparando o ambiente

Para melhor entendimento dos exemplos deste artigo criaremos uma tabela, com alguns dados e uma visão, que servirão como base para os testes que serão apresentados. A Listagem 1 contém o script para criação destes objetos.

O Script cria a tabela Funcionarios com algumas informações (ID, Nome, Salário, Telefone e Cidade) e, em seguida, são inseridos alguns registros. Logo após, uma view (vw_Funcionarios) é criada. A grosso modo, podemos dizer que Views são tabelas virtuais definidas por uma consulta T-SQL. A nossa view, criada na Listagem 1, retorna o nome e o salário de todos os funcionários que ganham mais de R$ 900,00.

Listagem 1. Script para criação dos objetos de teste


 CREATE TABLE Funcionarios(ID       Int IDENTITY(1,1) PRIMARY KEY,
                           Nome     VarChar(30),
                           Salario  Numeric(18,2),
                           Telefone VarChar(15),
                           Cidade   VarChar(80));
  
 INSERT INTO Funcionarios(Nome, Salario, Telefone, Cidade) 
 VALUES('José', 850.30, '11-55960015', 'São Paulo');
  
 INSERT INTO Funcionarios(Nome, Salario, Telefone, Cidade) 
 VALUES('Antonio', 950, '11-81115544', 'São Paulo');
  
 INSERT INTO Funcionarios(Nome, Salario, Telefone, Cidade) 
 VALUES('João', 1200, '11-44123321', 'São Paulo');
  
 CREATE VIEW vw_Funcionarios
 AS
   SELECT Nome, Salario FROM Funcionarios
    WHERE Salario > 900 

Query Optimizer

Quando um comando T-SQL é executado no SQL Server, o Query Processor entra em ação para gerar um plano de execução. Este plano dirá qual é a melhor maneira de acessar os dados gastando menos recursos e com o desempenho mais eficiente possível.

Podemos observar na Figura 1 a ação do Query Optimizer (em vermelho) e uma série de passos para compilar e executar um comando T-SQL. Vamos analisar melhor este comportamento.

Figura 1. Fluxograma de passos necessários para gerar um plano de execução

Supondo que um SELECT simples, por exemplo, SELECT * FROM Funcionarios, seja enviado ao servidor, a primeira tarefa que o Query Processor fará com o comando é verificar se o mesmo está no Cache Plan (mais informações sobre o Cache Plan no final do artigo). Caso ele não esteja em cache, o Query Processor enviará o comando para os processos de Parse e Bind.

O Parse/Bind executa um processo conhecido como Algebrizer. Durante este processo o SQL tenta encontrar possíveis erros de escrita na sintaxe e lógica do comando. Por exemplo, o comando “select id from tab1 group by nome” gera uma exceção, pois a coluna id não pertence ao group by e não está utilizando uma função de agregação (SUM, COUNT, ...). O Algebrizer também expande as definições do comando, isso significa que ele troca “select *” por “select col1, col2, col3...”, ou “select col1 from View” pelo nome das tabelas envolvidas na view.

Sempre que uma view é referenciada em uma consulta, o SQL Server acessa as tabelas que contém os dados. Na Figura 2, por exemplo, podemos visualizar que o SQL acessa a tabela Funcionarios para ler os valores das colunas Nome e Salario.

Figura 2. Ilustração de uma View acessando uma tabela.

Outro passo será resolver os nomes e tipos de objetos envolvidos na consulta. Pode acontecer de haver um sinônimo para uma determinada tabela que está em outro servidor. Quando isso acontece, o SQL precisa identificar que este sinônimo faz referência a um objeto que está em outro banco de dados, e este banco pode estar até mesmo ligado a outro servidor utilizando um Linked Server.

Após estas análises o Parse/Bind retorna um binário chamado Query Processor Tree, que é uma representação lógica dos passos necessários para a execução do comando SQL. O Query Processor Tree é enviado para o próximo passo da execução da consulta, que é a análise do Query Optimizer.

É importante destacar que nem sempre um comando é enviado para a análise do Query Optimizer. Por exemplo, alguns comandos DDL, tais como o CREATE Table, que são de definição das estruturas dos dados, não têm necessidade de uma análise do Query Optimizer, pois só há uma forma de o SQL executar esta operação.

...

Quer ler esse conteúdo completo? Tenha acesso completo