quarta-feira, 15 de setembro de 2010

Non-SARG que nada! Enganei o SQL Server...

Bom dia pessoal.

Prefere ler em PDF?




Ontem eu citei em uma palestra do Teched 2010 que um index seek exibido no plano de execução pode esconder na verdade um range scan ou até um full scan, então vou pegar um gancho de uma pergunta que apareceu recentemente em um treinamento que estava ministrando.

Explicando sobre non-search arguments eu demonstrei a consulta 01, que busca as vendas de um determinado mês. Porém sendo um non-sarg, o SQL Server utiliza o índice OrderDate (NCL) mas não faz um seek, e sim um NonClustered Index Scan, varrendo 4 páginas (o índice é muito pequeno).


Para resolver o problema, vamos alterar a consulta removendo o non-sarg, conforme a consulta 02, fazendo com que o SQL Server faça um seek (lendo duas páginas - raiz e folha) ao invés de um scan.


-- Consulta 01
SELECT orderdate, OrderID FROM Orders WHERE MONTH(OrderDate) = 07 and YEAR(OrderDate) = 1996


-- Consulta 02
SELECT OrderDate, OrderID FROM Orders WHERE OrderDate between '19960701' and '19960731 23:59:59.997'

Nesse momento um DBA fez uma observação muito curiosa: “eu posso enganar o SQL Server!” E para isso basta executar a consulta 03.

-- Consulta 03
SELECT OrderDate, OrderId FROM Orders WHERE MONTH(OrderDate) = 07 and YEAR(OrderDate) = 1996 and OrderDate > 0


Prontinho, se você olhar o plano gerado pelo SQL Server (figura 01) verá que ele está fazendo um index seek, ao invés do index scan gerado originalmente pelo non-sarg. Resolvido? No no no meu caro, na verdade não estamos enganando o SQL Server, infelizmente estamos sendo enganados.



(Figura 01)

Se olharmos com calma, o seek predicate é somente o “orderdate > 1990-01-01”, isto é, um belo scan no nosso índice não-cluster e enquanto o SQL Server está fazendo esse “seek”, ele vai tentando aplicar o predicado com MONTH e YEAR, que é o nosso non-sarg.


Putz, como eu sei que o SQL Server está fazendo um index scan? Dê uma olhada no STATISTICS IO e você verá o seguinte: “Table 'Orders'. Scan count 1, logical reads 4”. Hhhuummm, scan count = 1 (o SQL Server está fazendo um scan!) e logical reads = 4 é o mesmo que vimos durante a execução da consulta 01. Houve então alguma diferença efetiva no plano de execução? NÃO! Se você executar lado a lado a consulta 01 e a 03, verá um custo relativo de 50% para cada.


O que me incentivou a finalmente escrever esse post? Hoje cedo em vi que o time de CSS postou um artigo bem legal, chamado “SCAN COUNT meaning in SET STATISTICS IO output”, que explica um pouco sobre o scan count e serve de base para esse post, em que o “falso index seek” que é um full scan ou um range scan.

Espero que seja útil, e não deixe esses detalhes do SQL Server te enganar, ok? :-)
Abraços e até um próximo artigo.


[]s
Luciano Caixeta Moreira - {Luti}

Nenhum comentário:

Postar um comentário