Desmistificando o SELECT no SQL Server – Parte 1

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:

CREATE TABLE
	dbo.Cliente
	(
		 clienteID INT NOT NULL CONSTRAINT pkCliente PRIMARY KEY
		,cidade	VARCHAR(20) NOT NULL
	)
GO

INSERT INTO Cliente(clienteID,cidade) VALUES(1,'Brasilia');
INSERT INTO Cliente(clienteID,cidade) VALUES(2,'Brasilia');
INSERT INTO Cliente(clienteID,cidade) VALUES(3,'Brasilia');
INSERT INTO Cliente(clienteID,cidade) VALUES(4,'Goiania');
GO

CREATE TABLE
	dbo.Pedido
	(
		 pedidoID	INT NOT NULL CONSTRAINT pkPedido PRIMARY KEY
		,clienteID	INT NULL CONSTRAINT fkClienteID_pedido_cliente REFERENCES Cliente(ClienteID)
	)
GO

INSERT INTO Pedido(pedidoID,clienteID) VALUES(1,1);
INSERT INTO Pedido(pedidoID,clienteID) VALUES(2,1);
INSERT INTO Pedido(pedidoID,clienteID) VALUES(3,2);
INSERT INTO Pedido(pedidoID,clienteID) VALUES(4,2);
INSERT INTO Pedido(pedidoID,clienteID) VALUES(5,2);
INSERT INTO Pedido(pedidoID,clienteID) VALUES(6,3);
INSERT INTO Pedido(pedidoID,clienteID) VALUES(7,NULL);
GO

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:

SELECT DISTINCT TOP (<expressao_top>)
	<lista_select>
FROM
	<tabela_esquerda>  <tipo_de_join> JOIN <tabela_direita> ON <predicado_ON>
WHERE
	<predicado_WHERE>
GROUP BY
	<lista_group_by>
HAVING
	<predicado_HAVING>
ORDER BY
	<lista_ORDER_BY>

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:

		SELECT
			c.ClienteID as ID
		FROM
			dbo.cliente c
		ORDER BY
			ID

Query 2:

		SELECT
			c.ClienteID as ID
		FROM
			dbo.cliente c
		WHERE
			ID > 1

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

Advertisements

7 thoughts on “Desmistificando o SELECT no SQL Server – Parte 1

  1. Ótimo post muito didático e fácil de entender para quem está iniciando, você sabe se já exite uma versão em português para o 70-433 ou 70-641?
    Obrigado, abraço.

    • Caro Andrey, obrigado pelo feedback. Já existem outros posts que dão continuidade a série, e em breve irão sair mais!

      Quanto a sua pergunta, não entendi se você está se referindo ao livro ou as provas.]
      Se for livro, eu não encontrei nada, ou seja, acredito que realmente não tenha.
      Se for exame, a 70-433 tem somente em inglês, alemão e chinês! A 70-461 tem em português.

      Como recomendação, eu começaria a fazer as provas e estudos em inglês pois você não corre o risco de pegar traduções ruins. E pode apostar que isso te atrapalha até numa resposta de questão.

  2. Muito obrigado pelo retorno, na verdade eu queria saber sobre o livro e formulei mal a pergunta, mas você além de responder a pergunta já se adiantou a outra dúvida. Perfeito!
    Muito obrigado pelas resposta e por compartilhar seu conhecimento com tamanha eficiência e simplicidade.
    Abraços.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s