MCDBA Brasil


  • Home
  • Sobre
  • Contato

Livros





Links Rápidos

SQL Server Builds (All Versions/Editions)


Download SQL Server 2017 (trial)


SQL Server 2017 Feature Pack


SQL Server 2016 Feature Pack


Cumulative Update SQL Server 2017 builds


Cumulative Update SQL Server 2016 builds


Cumulative Update SQL Server 2014 builds


Cumulative Update SQL Server 2012 builds


SQL Server 2005/2008 Samples Databases


Documentando o Servidor SQL Server


Analisando a Performance do Servidor-CheckList


Virtual PASS PT


Faça parte do maior virtual chapter do PASS com conteúdos técnicos em Português sobre SQL Server.

Todos os meses um evento Online para você! Acompanhe aqui os WebCasts já agendados

Sindicalize seu blog ou site ao VirtualPASSPT

SQL Server Blogs

SQL Server Query Processing Team


SQL Programmability & API Development Team


SQL Server Manageability Team


Latin America Support Team


Database + Disk + Performance


Microsoft SQL Server Support


SQL CLR Team


SQL Query Optimization Team


SQL 2005 Code Samples


SQL Server Express Team


SQL SMO Samples


SQL Storage Engine Team


SQL CAT Team


SQL Protocols Team


PSS SQL Server Engineers


Slava Oks on SQLOS


Ken Henderson’s blog


LUTI@Microsoft Blog


kimberly L. Trip’s blog


Fernando Garcia Blog

Artigos

Querys Idênticas com Planos de Execução Diferentes

por Nilton Pinheiro janeiro 23, 2005 Nenhum comentário

Vamos ver alguns exemplos utilizando querys por data na tabela Orders do banco de dados Northwind, dois dos exemplos usam uma variável como argumento de busca, o outro um valor literal.


Exemplos:


— Query 1: Retorna 5 linhas, usando uma variável no argumento de busca
DECLARE @odate AS DATETIME
SET @odate = ‘19980506’
SELECT * FROM Orders
WHERE OrderDate >= @odate
GO

— Query 2: Retorna todas as linhas, usando uma variável no argumento de busca
DECLARE @odate AS DATETIME
SET @odate = ‘19960101’
SELECT * FROM Orders
WHERE OrderDate >= @odate
GO
— Query 3: Retorna 5 linhas, usando um valor literal no argumento de busca
SELECT * FROM Orders
WHERE OrderDate >= ‘19980506’
GO


As querys 1 e 2 usam uma variável local no argumento de busca. Já a query 3 usa uma referência ao mesmo valor que as querys 1 e 2 porém na forma de Hard-Code.


Execute as 3 querys no banco northwind para ter certeza que você conhece o retorno das 3 querys e como cada uma delas é diferente. Podemos observer que as querys 1 e 3 retornam o mesmo resultado, no entanto, ao verificarmos o plano de execução, veremos que cada uma contém um plano de execução diferente.


Quantidade de IOs efetuado pelas querys:


Agora execute as querys novamente, mas adicione o Statistics IO no inicio do Batch :


SET STATISTICS IO ON
GO


Resultado de IOs:
Query 1: Table ‘Orders’. Scan count 1, logical reads 40, physical reads 0, read-ahead reads 0.
Query 2: Table ‘Orders’. Scan count 1, logical reads 40, physical reads 0, read-ahead reads 0.
Query 3: Table ‘Orders’. Scan count 1, logical reads 10, physical reads 0, read-ahead reads 0.


Apesar das querys 1 e 3 retornarem a mesma quantidade de registros (4 registros), a query 1, que usa uma variável local, requer 40 leituras lógicas, enquanto que a query 3, que usa o valor umavalor literal, requer apenas 10 leituras lógicas. É possível notar também que a query 1 usa o mesmo número de leituras que a query 2, embora a query 2 retorne muito mais registros (830 registros).


Analisando o plano de Execução:


Agora execute as querys novamente, mas adicione o SHOWPLAN inicio do Batch.


Você pode ver o plano de execução (como o SQL Server executa cada query) a partir do query analyzer usando “SET SHOWPLAN_TEXT ON” no inicio do batch e usando “SET SHOWPLAN_TEXT OFF” no final.


Resultado do ShowPlan:


Query 1:
StmtText                                                                                                           
————————————————————————
  |–Clustered Index Scan(OBJECT:([Northwind].[dbo].[Orders].[PK_Orders]), WHERE:([Orders].[OrderDate]>=[@odate]))


Query 2:
StmtText                                                                                                           
—————————————————————————-
  |–Clustered Index Scan(OBJECT:([Northwind].[dbo].[Orders].[PK_Orders]), WHERE:([Orders].[OrderDate]>=[@odate]))


Query 3:
StmtText                                                                                                                            
——————————————————————————-
  |–Bookmark Lookup(BOOKMARK:([Bmk1000]), OBJECT:([Northwind].[dbo].[Orders]))
       |–Index Seek(OBJECT:([Northwind].[dbo].[Orders].[OrderDate]), SEEK:([Orders].[OrderDate] >= Convert([@1])) ORDERED FORWARD)



Podemos ver que as querys 1 e 2 possuem planos de execução identicos. Para executar essas querys, o SQL Server faz um scan na primary key (coluna orderID), que a clausula where não usa para nada. Já para executar a query 3 o SQL Server usa o índice não cluster OrderDate (definido na coluna orderdate) fazendo um index seek, isso explica a diferença no número de leituras lógicas entre as querys 1 e 3.


Mas afinal, por que o SQL server escolhe planos de execução tão diferentes para querys que parecem identicas ? O SQL Server não conhece o valor da variável local das querys 1 e 2 quando ele otimiza as querys, por isso ele tem que adivinhar o valor. Lembre-se, Indices nonclustered tipicamente não são úteis se temos a necessidade de retornar uma grande porcentagem de linhas de uma tabela, e apesar da query 1 retornar apenas 5 linhas, no momento de otimizar a query o SQL Server não sabe disso, então assume que a query irá retornar um terço da tabela, porque está sendo usando o operador >. Sendo assim, o índice nonclustered OrderDate não será eficiente pois a query returna muitas linhas, então o SQL Server não o utiliza.


Na query 3, o SQL Server conhece precisamente quantas linhas a query irá retornar porque o argumento de pesquisa (SARG) é literal. Sabendo que a query vai retornar apenas 5 linhas, o SQL server utiliza o índice nonClustered.


Uma fora de garantir que o SQL Server conheça o valor da variável em tempo de compilação e assim possa usar o índice correto, é encapsular a query em uma stored procedure. Você precisa utilizar a opção With Recompile para criar a stored procedure se o melhor query plan pode variar conforme os valores de entrada:


CREATE  PROC DateRangeTest
@odate AS DATETIME
WITH RECOMPILE
AS
SELECT * FROM Orders
WHERE OrderDate >= @odate
GO


Agora rode as seguintes instruções e compare o plano de execução de cada uma :


SET SHOWPLAN_TEXT ON
GO
EXEC DateRangeTest ‘19980506’
— returns 5 rows
EXEC DateRangeTest ‘19960101’
— returns 830 rows



Podemos ver que a primeira chamada da procedure, que retorna apenas 5 linhas, consegue utilizar o índice nonclustered OrderDate (fazendo um Index Seek), enquanto que a segunda chamada continua a fazer scan no indice clustered (PK_Orders) porque retorna um volume de linhas muito grande.


 

Avaliação:
Compartilhe:
  • Anterior Transaction Log21 anos atrás
  • Próximo O Desafio da Administração de Dados21 anos atrás

Deixe uma resposta Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

MVP Reconnect Award

Categorias

  • Artigos (359)
  • Dica da Semana (95)
  • Documentação (54)
  • Downloads (113)
  • MSDE 2000 (3)
  • Sem categoria (1)
  • Tutoriais (9)

Posts recentes

  • #FechouBrasil #PartiuPortugal
  • Brigando com o erro “The cached MSI file is missing”
  • MCDBABRASIL está de volta
  • Documentando o Servidor SQL Server
  • Brigando com os Erros 17182, 17826 e 17120

SQL Server AlwaysOn Video Series

Video1: Introdução ao SQLServer2012 AlwaysOn


Video2: Introdução ao SQLServer2012 AlwaysOn Availability Group


Video3: Introdução ao SQLServer2012 AlwaysOn AVG-Demo


Video4: Introdução ao SQLServer2012 AlwaysOn Listener


Video5: Introdução ao SQLServer2012 AlwaysOn Readable Secondaries


Video6: Introdução ao SQLServer2012 AlwaysOn Readable Secondaries-Demo


Video7: Introdução ao SQLServer2012 AlwaysOn Failover Clustering


Serie SQL Server Failover Clustering End-to-End

Parte 1: Configuração da Rede e Ambiente


Parte 2: Configurando o Windows 2008 R2 Domain Controler e DNS


Parte 3: Preparando os nós para o Failover Cluster


Parte 4: Configurando um Failover Cluster de 2 nós


Parte 5: Configurando as LUNs no iSCSI Software Target (Parte 1)


Parte 6: Configurando as LUNs no iSCSI Software Target (Parte 2)


Parte 7: Apresentando as LUNs para os nós do Failover Cluster


Parte 8: Configurando os discos no Failover Cluster


Parte 9: Instalando a primeira instância virtual do SQL Server 2008


Parte 10: Instalando a segunda instância virtual do SQL Server 2008


Parte 11: Instalando e Configurando o MSDTC no Failover Cluster


Parte 12: Configurando Mount Points no Cluster e SQL Server 2008


Vídeo Extra: Removendo uma Instância do SQL Server 2008 R2 em Cluster


Alta Disponibilidade no SQL Server 2008 R2: Failover Clustering Overview


Alta Disponibilidade no SQL Server 2008 R2: Failover Clustering na Prática

Menu

  • Home
  • Sobre
  • Contato

Mais

  • RSS Feeds
2026 MCDBA Brasil.