Tag Archives: sqlserver

FORCEPLAN – Utilização e explicação

Existe uma opção no SQL Server denominada FORCEPLAN que faz com que o SQL Server execute os joins na sequencia em que foram escritos na query.

O SQL Server Query Optimizer segue algumas heurísticas de otimização com a ajuda nas estatísticas para que seja encontrada a melhor tabela a ser lida primeiro para a conclusão de uma consulta, essa regra tende a ser a menor caso nenhum filtro seja aplicado. Abaixo um script e fotos da execução do FORCEPLAN.

--Object creation
IF(OBJECT_ID('Tabela01') IS NOT NULL)
	DROP TABLE Tabela01

CREATE TABLE Tabela01
(
	Id	INT	IDENTITY(1,1)	PRIMARY KEY,
	Nome	VARCHAR(100)	NOT NULL
)
	
IF(OBJECT_ID('Tabela02') IS NOT NULL)
	DROP TABLE Tabela02

CREATE TABLE Tabela02
(
	Id	INT	IDENTITY(1,1)	PRIMARY KEY,
	Sobrenome1	VARCHAR(100)	NOT NULL
)
	
IF(OBJECT_ID('Tabela03') IS NOT NULL)
	DROP TABLE Tabela03

CREATE TABLE Tabela03
(
	Id	INT	IDENTITY(1,1)	PRIMARY KEY,
	Sobrenome2	VARCHAR(100)	NOT NULL
)
GO

--Data load
INSERT INTO Tabela01(Nome)
SELECT CHECKSUM(NEWID())
GO 5000

INSERT INTO Tabela02(Sobrenome1)
SELECT CHECKSUM(NEWID())
GO 10000

INSERT INTO Tabela03(Sobrenome2)
SELECT CHECKSUM(NEWID())
GO 15000

--Sql query

--Sem forceplan
SELECT a.Sobrenome2, b.Nome, c.Sobrenome1
FROM Tabela03 a
INNER JOIN Tabela01 b
	ON (a.Id = b.Id)
INNER JOIN Tabela02 c
	ON (a.Id = c.Id)

Sem_Force_Plan

--Com forceplan
SET FORCEPLAN ON

SELECT a.Sobrenome2, b.Nome, c.Sobrenome1
FROM Tabela03 a
INNER JOIN Tabela01 b
	ON (a.Id = b.Id)
INNER JOIN Tabela02 c
	ON (a.Id = c.Id)

SET FORCEPLAN OFF

Com_Force_Plan

Ou seja, é possível observar que com o FORCEPLAN OFF a primeira tabela a ser lida foi a 01 pois possui apenas 5.000 linhas enquanto que após a ativação do FORCEPLAN para ON a primeira tabela a ser lida foi a 03 mesmo possuindo 15.000 linhas pois é a primeira tabela especificada em meu JOIN.

Outra característica interessante é que fisicamente com o FORCEPLAN OFF o método de join escolhido foi o MERGE JOIN, porem ao fazermos a alteração para FORCEPLAN ON temos apenas nasted loops, ou seja, ao habilitar o FORCEPLAN teremos priorização para Nasted Loops a não ser que seja especificado outro meio de join via join hint conforme script abaixo.

--Com forceplan e join hint
SET FORCEPLAN ON

SELECT a.Sobrenome2, b.Nome, c.Sobrenome1
FROM Tabela03 a
INNER MERGE JOIN Tabela01 b
	ON (a.Id = b.Id)
INNER MERGE JOIN Tabela02 c
	ON (a.Id = c.Id)

SET FORCEPLAN OFF

Com_Force_Plan_E_Join_Hint

Sua utilização ou não vai para cada cenário, eu particularmente não gosto pois estamos inibindo o Query Optimizer de fazer o seu trabalho alem de que será necessário muito mais conhecimento técnico e aprofundado do desenvolvedor no momento da programação.

Anúncios