Non search arguments no SQL Server


Algumas vezes o SQL Server não utiliza o plano de execução que você estava esperando e executa, por exemplo, um index scan onde era esperado um index seek. Um dos motivos desse comportamento pode ser a falta de índices (claro!), estatísticas desatualizadas ou problemas com a sua consulta, neste post vamos abordar um detalhe relacionado com o último problema.


O SQL Server possui o conceito de search arguments (SARG) que são condições da sua consulta que podem ser utilizadas para restringir o número de registros retornados para futura manipulação pelo plano de execução... Resumindo, é uma cláusula where que pode utilizar um índice para achar poucos registros (evitar um scan). O formato de uma SARG segue o padrão:


 


<Coluna> <operador_inclusivo> <constante ou variável>


ou


<constante ou variável> <operador_inclusivo> <Coluna>


 


O problema acontece quando utilizamos cláusulas negativas ou funções para definirmos nossos filtros (non SARG). Quando isso é feito a engine do SQL Server não utiliza os índices (mesmo que existentes e com estatísticas atualizadas) para fazer a consulta e trabalha com um table scan. PERFORMANCE!


Para demonstrar como isso funciona, montei um script com um exemplo baseado em um caso que encontrei nas andanças por esse Brasil. J


 


CREATE TABLE NonSARG


(


          Data DATETIME NOT NULL,


          Maquina VARCHAR(50) not null,


          Numero decimal null


)


 


ALTER TABLE NonSARG


ADD CONSTRAINT pk_NonSARG


PRIMARY KEY (Data, Maquina)


GO


 


DECLARE @Contador INT


DECLARE @Data DATETIME


 


SET @Contador = 0


SET @Data = '20060404'


 


WHILE @Contador < 10000


BEGIN


          INSERT INTO NonSarg VALUES (DATEADD(dd, @Contador, @Data), 'Maq' + CAST(@Contador AS VARCHAR(10)), 10)


          set @contador = @contador + 1


END


Go


 


Esse script cria uma tabela chamada NonSARG e insere 10.000 registros, todos com datas únicas e nomes de máquinas únicas. No query analyzer habilite a opção para exibir o plano de execução (Ctrl + K) e execute a consulta:


 


select * from NonSARG WHERE Data = '20061229'


 


|--Clustered Index Seek(OBJECT:([Inside].[dbo].[NonSARG].[pk_NonSARG]), SEEK:([NonSARG].[Data]=Convert([@1])) ORDERED FORWARD)


 


Como resultado temos 1 registro que foi localizado através de um index seek utilizando o índice PK_NonSarg, como esperado. Porém quando executamos a próxima consulta, a nossa cláusula where deixou de ser um SARG, pois utilizamos a função CONVERT no campo data.


 


select * from NonSARG WHERE CONVERT(char,Data,111) = '2006/12/29'


 


|--Clustered Index Scan(OBJECT:([Inside].[dbo].[NonSARG].[pk_NonSARG]), WHERE:(Convert([NonSARG].[Data])='2006/12/29'))


 


Neste caso toda a tabela é percorrida até que seja encontrado o registro com a data 29/12/2006.


Em uma tabela de exemplo com somente 10.000 registros o impacto disto é muito pequeno, agora se você pegar uma tabela de mais de 10 milhões de registros, com vários campos (= menos registros por página no nível folha do índice clusterizado) e sendo acessada por vários processos, a coisa pode ficar feia.


Imagine agora a quantidade de locks exclusivos se for executado uma instrução do tipo delete ... where convert(...) = ‘2006/12/28’. Égua!! A coisa não fica bonita não.


 


Portanto na hora de você escrever as suas consultas, preste atenção como estão sendo construídos seus filtros e sempre verifique como é o plano de execução.


 


Para mais informações sobre isso, leia o Inside SQL Server 2000 J e o artigo http://www.sqlmag.com/articles/index.cfm?articleid=42349&puuid=67C1FAFF-1279-906B-AC6CEF8FB0E24437


Em anexo está o script com o exemplo.


 


[]s


Luti

nonSARGs.sql

Comments (1)

  1. Ana Paula says:

    Nada técnico, apenas ri muiiito quando li o "égua" no meio do artigo, nem te entregastes! 😛

    abraços,

    Ana Paula

Skip to main content