quarta-feira, 15 de dezembro de 2010

Ordem dos Filtros vs Tempo de Execução

Frequentemente vejo desenvolvedores com dúvidas em relação à ordem dos filtros na cláusula WHERE das consultas. Algumas perguntas como; Se colocar um campo mais seletivo primeiro faz diferença? Se colocar a chave primária como primeiro filtro é mais rápido? A resposta é NÃO!!

Quando o SQL Server gera um plano de execução ele não faz isso por partes da consulta, ou seja, ele não sai lendo a consulta e montando o plano. O Query Optimizer que é o otimizador de consultas do SQL Server lê a consulta toda, completa e após isso gera o plano de execução, então a ordem dos filtros não altera o plano de execução, resumindo não afeta o tempo de execução da consulta.
Vamos ver na prática:

Use master
go
CREATE DATABASE Testes
GO
USE Testes
GO
CREATE TABLE Pessoa
(ID INT NOT NULL IDENTITY(1,1),
 NOME VARCHAR(100))
 GO

 --Inserindo registros na tabela Pessoa
INSERT INTO Pessoa VALUES ('Allyson')
go 1000
INSERT INTO Pessoa VALUES ('Joao')
go 1000
INSERT INTO Pessoa VALUES ('Rafael')
go 1000
INSERT INTO Pessoa VALUES ('Rodrigo')
go 101000

--Criando índice não cluster para os campos
CREATE INDEX IDX_Teste1 ON Pessoa (Nome, ID)
GO

--Limpando o cache
DBCC FREESYSTEMCACHE('ALL')

--Habilita as estatísticas de tempo, para verificar o tempo exato de passo da consulta
SET STATISTICS TIME ON

SELECT * FROM Pessoa
WHERE Nome = 'Rodrigo' and ID = 10000
GO

SET STATISTICS TIME OFF
Temos o resultado na aba de mensagens:
/*
SQL Server parse and compile time:
   CPU time = 0 ms, elapsed time = 4 ms.
SQL Server parse and compile time:
   CPU time = 0 ms, elapsed time = 0 ms.
(1 row(s) affected)
 SQL Server Execution Times:
   CPU time = 15 ms,  elapsed time = 8 ms.
*/  

--Limpando o cache
DBCC FREESYSTEMCACHE('ALL')

--Habilita as estatísticas de tempo, para verificar o tempo exato de passo da consulta
SET STATISTICS TIME ON

SELECT * FROM Pessoa
WHERE ID = 10000 AND Nome = 'Rodrigo'
GO

SET STATISTICS TIME OFF

Temos o resultado na aba de mensagens:
/*
SQL Server parse and compile time:
   CPU time = 0 ms, elapsed time = 3 ms.
SQL Server parse and compile time:
   CPU time = 0 ms, elapsed time = 0 ms.
(1 row(s) affected)
 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 8 ms.
*/  

Vemos então que o tempo foi exatamente igual para as duas consultas. Sendo que na primeira fazemos o primeiro filtro pelo Nome='Rodrigo', onde existem mais de 100.000 ocorrências, e depois fazemos novamente onde o primeiro filtro é o ID, como foi criado como identity ele é único na tabela, e o tempo de execução foi mesmo.

O que ocorre frequentemente é que quando executamos uma consulta o seu plano de execução vai pro cache e quando alteramos a ordem dos filtros e não limpamos o cache a consulta é executada mais rápido por seu plano já está em cache e dá a impressão de que a ordem dos filtros fez diferença.

É muito importante quando se está analisando uma consulta limpar o cache, para não se enganar com o resultado.

Abraços,
Rodrigo Figueiredo
figueiredo.rodrigo@hotmail.com