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

Index Seek em Where com função?Como?

por Nilton Pinheiro novembro 3, 2009 Nenhum comentário

Bom, com a situação acima um index scan era feito na consulta e tinha um custo altíssimo de IO (logical reads altos e physical reads também) e realmente travava  a galera quando rodava (agendada para execução de 1 em 1 hora por um job) e demorava 20 minutos. Ou seja, 20 minutos que parava. Como foi resolvido?

Usando uma computed column e um índice nesta computed column!


Para vocês entenderem melhor a solução implementada, vamos lá ..criando o ambiente:


• Criar uma tabela com um campo Case Sensitive


create table TesteComputed
(codigo int identity Primary key Clustered,
Valor1 decimal(10,2),
Valor2 decimal(10,2),
Nome varchar(100) Collate Latin1_General_CS_AS
)
GO

• Criar o Indice na tabela , campo Nome


create index idx_TesteComputed_Nome on TesteComputed(nome)
 
• Popular a tabela usando uma CTE


;WITH ComputedCte (Id, CteValor1, CteValor2)
AS
(SELECT    1,
ABS(CheckSum(NEWID()) / 1000000.8764),
ABS(CheckSum(NEWID()) / 2000000.7652)
UNION ALL
SELECT id+1,
ABS(CheckSum(NEWID()) / 1000000.8764 ),
ABS(CheckSum(NEWID()) / 2000000.7652)
FROM ComputedCte
WHERE id < 31000
)
insert into TesteComputed(Valor1,Valor2,Nome)
Select    Ctevalor1,Ctevalor2,
CASE
when Ctevalor1 between  1 and 999 Then ‘Campo2’
when Ctevalor1 between  1000 and 10000 Then ‘Campo1’
when Ctevalor1 between  12000 and 20000 Then ‘Campo2’
END
FROM ComputedCte
OPTION (MAXRECURSION 31000)       


Agora vamos aos testes…


Se eu montar esta consulta sem o UPPER vamos ver como fica…
 
SELECT nome
FROM TesteComputed
WHERE Nome = ‘Campo1’


(16632 row(s) affected)


Abaixo pode-see ver o plano de execução no modo texto


Table ‘TesteComputed’. Scan count 1, logical reads 45, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


SELECT [nome] FROM [TesteComputed] WHERE [Nome]=@1
  |–Index Seek(OBJECT:([DBA].[dbo].[TesteComputed].[idx_TesteComputed_Nome]), SEEK:([DBA].[dbo].[TesteComputed].[Nome]=CONVERT_IMPLICIT(varchar(8000),[@1],0)) ORDERED FORWARD)


Além do que se eu não colocar o ‘Campo1′ com a primeira letra em maiúsculo como está na tabela, não me retornará nada, pois a coluna é case-sensistive.


Agora usando o UPPER…


SELECT nome
FROM TesteComputed
WHERE UPPER(Nome) = ‘CAMPO1’


(16632 row(s) affected)


Table ‘TesteComputed’. Scan count 1, logical reads 81, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


select nome   from TesteComputed  where upper(Nome) = ‘CAMPO1’
  |–Index Scan(OBJECT:([DBA].[dbo].[TesteComputed].[idx_TesteComputed_Nome]),  WHERE:(upper([DBA].[dbo].[TesteComputed].[Nome])=’CAMPO1′))


Podemos ver bem que o logical reads aumentou e ao invés de um seek estamos fazendo scan agora.


Vamos transformar esse scan em um seek ainda usando o upper no where?


• Crie mais um campo na tabela, este campo sera um campo calculado. Ele terá o UPPER do campo nome.


Alter table TesteComputed add UpperNome as UPPER(nome)
 
• Crie o indice neste campo calculado e atualiza as estatisticas com fullscan (não é necessário, mas é altamente recomendável – vai demorar um pouquinho)


create index idx_TesteComputed_uppernome on TesteComputed(uppernome) include (nome)
GO
update statistics TesteComputed with fullscan


Agora, rodando a mesma consulta temos o seguinte…


(16632 row(s) affected)


Table ‘TesteComputed’. Scan count 1, logical reads 60, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


select nome   from TesteComputed  where upper(Nome) = ‘CAMPO1’
  |–Index Seek(OBJECT:([DBA].[dbo].[TesteComputed].[idx_TesteComputed_uppernome]), SEEK:([DBA].[dbo].[TesteComputed].[UpperNome]=’CAMPO1′) ORDERED FORWARD)


Ta aí..temos um index seek!


Bom, isso foi extrema valia para mim, pois consegui resolver sem precisar acionar o suporte da empresa numa sexta a noite.


Desta maneira, aquela consulta que demorava 20 minutos e tinha aproximadamente 800.000 logical reads e 180 physical, caiu para 130.000 reads (movimentava uma quantidade grande de linhas) e 0 physical reads, reduzindo o tempo da consulta para 1 minuto e meio.


Em breve estarei postando sobre alguns outros casos de sucesso que tive usando colunas computadas, neste mesmo projeto.


Um abraço !!!!
Laerte Poltronieri Junior
$hell Your Experience !!!
www.laertejuniordba.spaces.live.com

Avaliação:
Compartilhe:
  • Anterior How To Became an Exceptional DBA usando Powershell Parte I16 anos atrás
  • Próximo Fazendo peripécias com o arquivo de trace do Profiler usando POWERSHEL16 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
2025 MCDBA Brasil.