THE SQL TIMES

Respondendo os porquês sobre SQL Server, Windows, programação e outros assuntos sobre tecnologia

2. Desmistificando o SELECT no SQL Server: Processamento Lógico vs Processamento Físico

Post 2/5. Este post é parte da série: Desmitificando o SELECT no SQL Server

Quando eu começei a ler sobre o processamento lógico das queries, eu “boiei” muito.
Sabia que era um assunto bem legal, mas nao entendia realmente o que era.

Depois de algum tempo de leitura e pesquisa, acho que finalmente entendi, e, por experiencia própria acredito que seja mais do que importante entender bem esse assunto.

Para o SQL Server processar aquele comando SQL, ele tem algo como “regras”.
Ele vai validar o comando pra ver se está de acordo com a sintaxe do SQL, checar se as tabelas existem, etc…

Todo esse procedimento segue uma lógica. Essa lógica guia o modo como a engine do SQL Server irá interpretar o comando.
Por exemplo, veja a seguinte query: (Os scrips para criação dessas tabelas estão aqui)

 

É uma query muito simples. O que ela faz é trazer a quantidade de pedidos por cidade.
Vamos viajar um pouco. Imagine que você fosse o SQL Server e estivesse responsável por processar a query.
De cara, você começa a processar a query a partir do início, isto é, da cláusula SELECT:

Ai você dá de cara com esse primeiro trecho do comando:

 

Ai você se pergunta, “C.cidade” ? Qual tabela o alias “C” representa ?
Opa, você percebeu que nao podemos começar o processamento pelo SELECT, porque primeiro precisamos saber quais as tabelas e alias o desenvolvedor informou na query.  E onde estão essas informações ? Na cláusula FROM!!

Para simplificar, podemos dizer que o “processamento lógico” é a ordem em que o SQL Server irá ler as cláusulas do seu comando SELECT. Essa ordem, pode interferir nos resultados que a sua query vai produzir.

Agora veja esta outra query:

Este comando SELECT pode ser dividido em 4 sub-comandos, ou cláusulas:

  • SELECT: Esta parte contém a lista de colunas que queremos retornar, bem como as expressões, e a opção “DISTINCT”.
  • FROM: Esta parte contém as tabelas  com as linhas e colunas que vamos acessar.
  • ORDER BY: Este comando diz que devemos ordenar os resultados conforme uma ou mais colunas

Essa query pode ter várias interpretações diferentes, isto é, várias “lógicas de processamento” diferentes, dependendo da orgem como estes sub-comandos são processados. Cada lógica escolhida no seu processamento vai produzir um resultado diferente. Quer ver ? Então vamos lá.

Vamos supor que a lógica de processamento que voce escolheria fosse a seguinte: (de novo, imaginando que você  é o SQL Server)

1º – FROM
2º – ORDER BY
3º – SELECT
Bem vamos lá, o FROM seria moleza. Você teria apenas que ler os dados da tabela Cliente e atribuir o alias “C” a ela. Logo em seguida viria o ORDER BY. Opa, temos um problema, a tabela Cliente nao tem uma coluna ‘NomeCidade‘. Essa coluna é um alias definido no SELECT, e como você ainda não processou o SELECT, não sabe da existencia desse alias. Nesse caso, representando o SQL Server, o que fazer? Simples: Informaria um erro ao usuário:

“Erro 0000: A coluna NomeCidade nao foi encontrada”

Assim, nessa ordem de processamento, o resultado seria um erro. Agora, vamos imaginar que a ordem escolhida fosse essa:

1º – FROM
2º – SELECT
3º – ORDER BY

De novo, a primeira fase é processar o FROM: apenas ler tabela Clientes e atribuir o alias “C” a ela.
Agora, vem a fase do SELECT. Nessa parte ele menciona “C.cidade”. Como já processamos o FROM, sabemos que o “C” representa a tabela “Cliente”. Legal, com isso nós vimos que o desenvolvedor está querendo referenciar uma coluna chamada “cidade” da tabela Cliente. O próximo passo seria verificar se a coluna realmente foi retornada pelo FROM, mas não se preocupe com isso agora. Continuando o processamento do SELECT, aplicariamos a funcao UPPER na coluna “C.cidade”. Depois, nós iríamos associar o alias “NomeCidade” ao resultado desta função e finalmente realizar o “DISTINCT” nas linhas resultantes. Terminando a parte do SELECT, processaríamos o ORDER BY. Como já processamos o SELECT, nó sabemos que o nome “NomeCidade” é uma alias pro resultado da expressão “UPPER(C.Cidade)”.

Agora é so ordenar os dados de acordo com o resultado dessa função, e pronto! Tá vendo ? Olhe só que interessante: Na primeira tentativa, o nosso processamento resultou em um erro. Na segunda, apenas por trocar o ORDER BY de lugar com o SELECT, ja produziu um resultado sem erros. Isso não se resume a resultados com erros ou não.

Mais um exemplo, outro simples SELECT:

Se eu estivesse aprendendo banco de dados agora, e te perguntasse o que esse código faz, provavelmente você diria: “Retorna o ID e cidade de todos os registros da tabela ‘Cliente’ ”. E está certo! Você sabe o que vai ser retornado. Agora se eu te perguntasse, como o SQL Server está fazendo para acessar estes dados você poderia me responder: “Ele está lendo a tabela inteira diretamente”, ou “Ele está usando o índice da tabela”. Não importa como o SQL Server está fazendo, mas você sabe que o que ele está tentando fazer é ler a tabela inteira, e retornar 2 colunas. Independente de como ele vai fazer isso, porque é isto que a query está pedindo.

Agora, imagine que você quisesse saber o seguinte:

Trazer todas as cidades da tabela cliente, junto com o total de pedidos feitos por clientes cujo ID é < 3

Em uma primeira tentativa, a query abaixo poderia ser uma solução:

 

 

Percebam que a cidade “Goiânia” não aparece no resultado, e a nossa regra de negócio exige que ela apareça (“trazer todas as cidades”). Mas porque ? Onde está o problema ? A coisa fica mais interessante quando você apenas muda um filtro de lugar …

 

Agora sim o resultado retornado foi o que queríamos. Porque apenas ao mudarmos o filtro de lugar o resultado produzido foi diferente? Isso fica facilmente entendido quando você entende que o SQL Server processa o WHERE APÓS o FROM. O filtro que você faz no WHERE afeta os resultados do JOIN. Já no segundo exemplo, o resultado produzido pelo JOIN respeita o filtro que você fez na cláusula “ON”. Você irá entender melhor o que ocorreu nos próximos posts.

Conforme visto neste post, o processamento lógico divide o comando SELECT e todas as suas opções em algumas fases. Nos próximos posts, iremos abordar fase por fase. Cada fase produz um resultado, que não é visível por seu código, apenas pelo SQL Server, internamente. Este resultado é passado para a próxima fase, e isso vai se repetindo até que se acabem as fases a serem processadas. Se uma fase não existe, o SQL Server apenas pula e repassa a tabela virtual.

Tabelas Virtuais

No processamento lógico cada fase produz um resultado e esse resultado é passado para a próxima fase. Para facilitar, imagine que cada fase produz uma tabela virtual. Eu não vou chamar de “temporária” para você não confundir com as tabelas temporárias que existem no SQL Server. Essas “tabelas virtuais” são passadas de fase por fase, e a próxima fase só enxerga a tabela que foi passada a ela, inclusive somente as suas colunas (tem algumas exceções, mas esqueça por agora). Por questões de nomenclatura, eu vou atribuir nomes a estas tabelas virtuais para ir facilitando nossa compreensão, mas lembre-se que essas tabelas só são “enxergadas” pelo SQL Server internamente.

As tabelas virtuais são um conceito que iremos utilizar para representar os resultados passados de uma fase para outra

As tabelas virtuais são um conceito que iremos utilizar para representar os resultados passados de uma fase para outra. Cada fase pode receber uma tabela virtual e gerar outra que será repassada para a próxima fase. Esta nova, poderá nem sempre será igual a que recebeu.

Entender como a sua query é processada/interpretada pelo SQL Server irá te ajudar a prever os resultados e ter domínio sobre o código que está escrevendo, já que você saberá qual vai ser o fluxo a ser seguido. É por isso que é bastante importante entender como o SQL Server irá avaliar seu comando SQL. Entender o processamento lógico da query é a chave, o primeiro passo, para escrever consultas mais eficientes e robustas.

E o processamento físico ?

O processamento lógico, como disse anteriormente, é apenas a ordem em que o SQL Server irá ler o seu comando SQL… Nesta fase, o SQL Server apenas vai entender “o quê” tem de ser feito, onde estão os dados que devem ser acessados e que transformações devem ser aplicadas nele. O processamento físico é “como” o SQL Server vai fazer isso. Ele pode criar atalhos (isto é, otimizar) o caminho normal do processamento lógico se há garantias que esses atalhos irão produzir o mesmo resultado caso os mesmos não fossem seguidos (tudo isso é fortemente estuado pela equipe de desenvolvimento do SQL Server). Essa parte é feita por um componente chamado “Query Optimizer”, o cara que gera os famosos”planos de execução” (que indica como o SQL irá executar a query)  para as queries.

Para esta série você apenas precisa saber que o resultado produzido pelo processamento físico deve ser exatamente o mesmo produzido no processamento lógico. Assim, quando formos analisarmos o plano de execução iremos ver passos em uma ordem muito diferente do processamento lógico, mas pode ter certeza que o resultado produzido, será o mesmo do processamento lógico. Também, não se preocupe quando o processamento lógico parecer algo absurdo, basta lembrar que aquilo “é um esqueleto” do que será feito realmente.

Bom, espero que esse post nao tenha ficado confuso. Esse lance de processamento físico e lógico vai ser esclarecido conforme formos vendo cada fase do processamento lógico. Qualquer dúvida, sugestão, crítica, etc., por favor, coloque nos comentários que estarei respondendo.

Até a próxima.

[]’s
Rodrigo Ribeiro Gomes
MTA|MCTS

1. Desmistificando o SELECT no SQL Server: Introdução

Post 1/5. Este post é parte da série: Desmitificando o SELECT no SQL Server

Salve galera. Desde que os dinossauros morreram, eu não posto nada aqui! Bom, a causa é a vida , etc… Mas pretendo voltar a ativa.

Agora que realizei um pequeno sonho (passei no exame 070-432) pretendo escrever mais,  compartilhar mais, para aprender mais,e  é claro, tentar mais provas 🙂

Hoje vou iniciar uma série de posts que eu acredito que possa ajudar muitos desenvolvedores. Umas das maiores dificuldades que já vi, é entender como funciona o processamento das nossas queries, internamente no SQL Server. Isso é a chave para escrever consultas mais eficientes. É por isso que inicio a série:  “Desmistificando o SELECT no SQL Server”.

Pra me ajudar conto com o livro Inside SQL Server 2008: T-SQL Querying e o BOL. Se eu usar alguma outra fonte, vou citar. É claro que isso não é uma aula, e sim uma forma de exercitar e compartilhar o que estou aprendendo também. Portanto, estou sujeito a erros, e os comentários estão ai pra gente conversar!!!

Irei usar os exemplos do livro, adptando-os para uma realidade mais brasileira :).
O cenário é simples: Uma tabela de clientes e uma de pedidos (pra variar…).
Os scripts para a criação das tabelas e população que irei usar, estão aqui:

 

Irei usar SQL Server 2008. Mas boa parte disso tudo vale para o 2005 também. Irei citar os momentos em que houver alguma diferença grande.

Nestes posts irei falar sobre o processamento lógico da query. Pra algumas pessoas que já conhecem alguns detalhes, como o plano de execução, podem ficar confusas com a ordem do processamento. Mas desde já adianto que existe uma diferença entre o processamento físico e lógico. Vamos nos concentrar somente no processamento lógico da coisa.

Pra começo de conversa, a sintaxe básica de todo comando SELECT, no SQL Server, é assim:

Estamos acostumados a ver que a maiorias das linguagens, seja compilada ou interpretada, ler o código do início e compila/interpreta a partir desse início.

Com o SQL é diferente. Cada cláusula gera uma saída, que pode ser uma tabela virtual (que só é acessada internamente pelo sql), ou um cursor (não é o mesmo cursor que estamos acostumados a ver, é interno). Essa saída é usada pela próxima etapa, no caso de uma tabela virtual, ou é enviada ao cliente, no caso do cursor. A ordem dos comandos a ser executada será essa:

——————————————————————————————
1º – FROM
É aqui que os JOINs serão processados. Os filtros da cláusula ON também serão avaliados e por fim, essa etapa irá gerar uma tabela virtual.

2º – WHERE
Como todos já sabem, o WHERE responsável por aplicar os filtros na tabela virtual gerada pelo FROM. É gerada uma nova tabela virtual aqui.

3º – GROUP BY
O GROUP BY pega a tabela virtual gerada no WHERE e agrupa as linhas conforme soliticado.
Outra tabela virtual é gerada.

4º – HAVING
Aqui serão aplicados os filtros baseados em funções agregadas. Uma tabela virtual com as colunas que passaram nos filtros é gerada.

5º – SELECT
Finalmente, as expressões contidas no SELECT são avaliadas. Isso inclui os alias que damos as colunas. DISTINCT e TOP também são processados nesta etapa. Uma tabela virtual é gerada.

6º – ORDER BY
Por fim, o ORDER BY faz a ordenação dos registros para serem apresentados. A saída dele é um cursor que será retornado ao cliente que está executando a query.
——————————————————————————————

Um efeito interessante disso tudo é fácil de perceber:

Query 1:

 

Query 2:

Query 1 rodou!!!

Resultado da execução da Query 1

Query 2 não rodou- Erro: Invalid column name 'ID'

Resultado da execução da query 2

Por que a primeira query dá certo, e a segunda não ?
Simples: Lembra que eu disse que é na fase do SELECT que os alias são avaliados ?

ORDER BY é processado depois do SELECT. Assim quando o código chega no ORDER BY ele já tem a coluna com o nome “ID” associada com sua expressão.

Como o WHERE é processado antes do SELECT, ele não sabe o valor ou expressão que “ID” representa.

Bom, aqui eu me despeço mais uma vez. Nos próximos posts irei falar sobre cada etapa separadamente. O próximo será sobre o FROM. Irei mostrar o porque o LEFT JOIN é tão chato as vezes…

/** UPDATE 25/02/2012  

Antes de dar inicío ao post sobre FROM, resolvi dar um foco melhor a esse lance de “processamento lógico da query”.  

O próximo post fala sobre isso, e pode ser visto aqui.

**/

[]s
Rodrigo Ribeiro Gomes
MTA | MCTS

E se Chuck Norris fosse DBA ?

Para distrair um pouco: recentemente eu encontrei um post muito engraçado ( para os que entendem ) sobre o famoso Chuck Norris versão DBA.

Abaixo uma prévia do que pode ser encontrado nesse blog:

[…]
  • Chuck Norris não faz DELETEs. Ele olha para os registros e eles correm de medo.
  • MSSQL Server É muito mais rápido que Oracle. Basta que o DBA seja CHUCK NORRIS.
  • SELECT SUM(FORÇA) FROM CHUCK_NORRIS;
    Internal error. Don’t call the support.
  • SELECT CHUCK_NORRIS;
    Drop database sucessful.
  • Chuck Norris instala o MSSQL Server em um Pentium 100MHZ. Rodando Solaris. A partis dos fontes.
  • Se disser ao DBA Chuck Norris que “o problema está no banco”, é melhor que esteja se referindo ao Itaú.
  • TRIGGERS tem este nome porque Chuck Norris sempre ameaçava atirar no banco quando ele não fazia algo automático.
[…]

[]s
Rodrigo Ribeiro Gomes

Uma imagem vale mais do que 10000000 linhas !

Olá, tudo bem ?

É no espírito de Paulo Henrique Amorim que começo ( na verdade continuo ) mais um post.

No último post eu falei sobre um recurso chamado Query Shortcut que pode facilitar a vida de desenvolvedores e DBAs na hora de debugar, criar, alterar as querys.

Existe uma outra ferramenta bastante bacana que também pode facilitar a vida[2] e muito dessa galerinha. Estou falando do SMSS Tool Pack. Não vou citar todos os recursos, até porque é uma ferramenta que começei a utilizar a pouco tempo. O que eu posso adiantar aqui é que é GRÁTIS. Claro que nao vou terminar isso sem mostrar um preview né.

Essa ferramenta é uma espécie de plug-in pro Management Studio (SMSS) que adiciona algumas novas funcionalidades. Dentre elas, a que eu mais gosto, é a de colorir a janelinha do query editor de acordo com a conexao. Por que isso é tão útil assim ? Sabe aquelas horas em que você está fazendo um teste, e vai rodar aquele DELETE inonfensivo em um servidor de teste, mas quando aperta o F5 se dá conta que estava na conexao de produção ? Pois é, talvez se tivesse uma faixa imensa vermelha na sua frente, você pensaria 3 ou 30 vezes antes de apertar o tal do F5 … tipo assim:

Colorindo a janela de acordo com a conexao

E é claro que no dia-a-dia, nessas correrias, e com o mercado querendo mais em menos tempo, estamos sujeitos a essas situações nem um pouco agradáveis …

Você configura uma cor pra um determinado texto. Toda vez que uma conexao for feita e conter exatamente aquele texto, a cor vai ser aplicada. Você também pode usar o tal texto como expressão regular, facilitando ainda mais no caso de vários servidores com um nome em comum. Além de especificar uma cor, você pode configurar  largura da faixa, entre outras opções:

SMSS Tool Pack - Opções do "Window Coloring"

Existem muito outros recursos como gerar INSERTs, modelos de querys ( que serao adicionados toda vez que a conexao abrir ), manter um histórico das últimas querys executadas, mesmo que você não tenha salvo ( esse é ótimo, descobrir alguns dias atrás ), etc… Prefiro que você descubra, afinal, é simples e rápido !

Essa ferramenta é um pouco fresca, ela exige que se tenha o SQL Server 2005 Service Pack 2 ou posterior (Não instale sem atualizar, porque além do plugin nao funcionar, vai ficar uma janelinha chata , enchendo o saco toda vez que você abrir o SMSS). Disponibilizo alguns links pra atualização ( fica a seu critério escolher, mas recomendo sempre o mais atualizado, nesse caso o Service Pack 3 ):

Versão Express:
SQL Server Management Studio Express Service Pack 2
SQL Server Management Studio Express Service Pack 3

Outras Versões:
SQL Server Service Pack 2
SQL Server Service Pack 3

A versão SP4 foi lançada recentemente, só que está em versão RTM, que é somente para testes, quem quiser pode encontrar aqui (versão não express). Para Outras Versões (as pagas $$) o instalador é o mesmo, tanto pro Management Studio, quando pro próprio SQL Server, o instalador irá procurar os produtos do SQL Server 2005 instalados e irá atualizar o que for necessário.

Bom espero que isso sirva pra alguém algum dia !

[]s
Rodrigo Ribeiro Gomes

Query Shortcuts

Salve povo !
Expediente acabou, estou indo embora e queria deixar uma dica.

As vezes a gente nao se importa com algumas ferramentas que agilizam nossas vidas quando o assunto é programação. Principalmente quando você tem que ficar repetindo várias vezes as mesmas ações.

Uma coisa comum que a maioria dos desenvolvedores de SQL Server faz é usar SPs ( Stored Procedures ) para retornar informações do servidor, definição de outras procedures, triggers, etc. Um exemplo comum é o uso de sp_helptext. Qual desenvolvedor nunca usou isso ? Ou sp_lock, ou sp_who2 ? Qual DBA nunca usou ?

A questão aqui é quando o uso é constante, como no caso de sp_helptext (e das outras também, hehe). É bastante chato, pelo menos eu acho, quando a gente quer mccher mexer em alguma procedure e tem que ficar escrevendo sp_helptext ‘NOME_DE_UMA_PROCEDURE’. E pra quem copia e cola, é chato do mesmo jeito.

Não, chega disso. Para os usuários do SMSS, ele oferece um recurso “Query Shortcurts”, onde você configura um atalho para uma procedure, isto mesmo, uma combinação de teclas, e quando essa combinação de teclas é pressionada, ele executa a procedure na conexao atual !!!!!!!!! E detalhe, se a procedure tiver parâmetros, basta você selecionar os parâmetros, e usar o atalho, que ele vai pegar o texto que está selecionado e enviar como parâmetro.

Pra demonstrar isso,  eu vou criar uma procedure qualquer aqui…

USE master
GO

CREATE PROCEDURE prcQualquer
AS
print 'SQL Server'

Bom, uma SP simples, que apenas imprime algo na tela. Se eu quisesse ver a definicao dela, eu faria algo assim:

sp_helptext 'prcQualquer'

Executando sp_helptext

Usando o Query Shortcut, bastaria apenas usar o atalho com o nome “prcQualquer” selecionado,e apertar a combinação de teclas. Legal né ? Eu nao vou entrar em detalhes aqui o quanto isso pode ser útil, vou deixar você descbrir. Se não achar útil, tudo bem, mas eu vou continuar achando. 😉

Ahh, e onde configura isso ? Simples, sabe o menuzinho onde tem “File”,”Edit” ? Procura um chamado “Tools”:

Tools->Options

Tools->Options-

Dái vai abrir essa janelinha aqui:

Environment->Keyboard

Configurando as Query shortcuts

Algumas já vem configuradas por padrão, como sp_lock.Nesse caso eu coloquei sp_helptext em CTRL + F1. Agora toda vez que eu apertar CTRL + F1 dentro do editor de query, ele vai executar a procedure sp_helptext. Como a procedure necessita de alguns parâmetros, você precisa selecionar algo, se não dá erro.

Usando o queryshortcut

Se estiver algum aba de query aberta, o atalho nao funcionará, somente para as novas abertas. Você também nao fica limitado a stored procedures, você pode colocar um SELECT, INSERT, isto é, qualquer T-SQL válido.

Bom pessoal, é isso, num próximo post eu falo sobre algumas outras ferrmentas, té a próxima.

Ahhh, pra quem viu o post anterior, eu disse :

[…]”quando acabar a merda de algum teste lembra de desfazer as coisas que fez”[…]

Então …

USE master
GO

DROP PROCEDURE prcQualquer
GO

[]s
Rodrigo Ribeiro Gomes