Fabiano Neves's profileFabiano Neves Amorim - S...PhotosBlogListsMore Tools Help

Fabiano Neves Amorim - SQL Server

SELECT * FROM MinhaCabeca WHERE Coisas LIKE 'SQL%' AND TempoLivre >= dbo.fnTempoParaUmPost()

Fabiano Neves Amorim

Occupation
Location
About Me –

Infatuated by SQL Server specialty to the Query Processor(I love know how it works) and in Optimize querys, procs, functions…
Deployment Data Warehouses whit Analysis Services and SQL Server.
Deployment of projects/solutions in Delphi and .NET Plataforms.
Graduated as Technical Processor from Colégio Bezerra de Menezes, I has worked some years as SQL Server focus in creating Data WareHouses to many companies in Brazil. Right after that, I’m working as Database Solution for a Microsoft Solution Gold Partner. Beyond that I also is a MCP, MCTS and MCITP Data Base Developer at SQL Server 2005. I’ve one technical blog about SQL Server (http://fabianosqlserver.spaces.live.com/) - exclusively focused on DBA's, developers and SQL Server users. I also effectively participle on foruns like SQL Server from MSDN and TechNet Brazil, and teach WebCasts to Microsoft Brazil.

Custom HTML

Fabiano Neves Amorim - SQL Server

Loading...Loading...
Blog de alguns funcionários da MS que trabalham com SQL Server
Diversos Times do SQL Server
July 01

Em um projeto não muito distante….

Galera, a alguns meses atrás escrevi que estava participando de um projeto bem interessante e que logo eu postaria algumas novidades em relação a ele.

Bom, faz tempo que estou querendo escrever este post... tenho certeza que muitos que estão lendo vão se identificar com as situações que encontramos em nosso dia a dia.

Coisas que rolaram no projeto

Frases que ouvi:

– Eu não mexi em nada! Só apertei o OFF. (Essa foi f. Então mexeu caramba, rs...)

– Faz um Cola e Copia.(Umm? Não seria Copia e Cola? rs)

– Mas posso fazer o backup com os usuários logados na base? Não vai derrubar todo mundo?

DataCenter que ganha mais de 150 reais hora pra administrar o banco SQL liga de madrugada. – Esta faltando espaço no disco do servidor SQL. Vou dar uma olhada, .... Arquivo de paginação no C: com 16 GB, detalhe, era o tamanho padrão.... 5 GB de dados na lixeira WTF...

Como mania, rodo um DBCC SHOWCONTIG em uma de nossas maiores tabelas só pra ver como andam as coisas... resultado?

Densidade da Verificação [Melhor Contagem : Contagem Real].......: 12.14% [1521:15869]

Havia um script rodando a mais de 2 dias e meio, daí vieram me falar... – Ou aquele script que enviaram esta rodando no servidor a mais de 2 dias e não termina. Na hora já falei, - Para meu!, ta em LOOP infinito. Fui ver... batata, ainda estava no primeiro registro, hahuauauhua.

Não pude usar SSIS e criptografia MD5(aqui até tive que concordar um pouco).

Reuniões e mais reuniões com pessoas que não decidem, para decidir qualquer coisa que não precisava ser decidida naquela hora, e que futuramente, seria decidido que seria feito de maneira diferente do que foi decidido. Com pessoas que falam assim:

- Anyway, pelo feedback de nossos customers, na reunião do GO to GO vamos ter que adiar o esclarecimento com os PMOs para a próxima meeting.

Em uma das conversões, fiquei 36 horas online direto no cliente só na base do café :-). E no fim de tudo, a conversão não deu certo e escutamos um sermão(com razão) de nosso Diretor que havia ido pro cliente pra ver como estava o projeto.

Coisas que aprendi, e outras que deram certo.

Fizemos um script de mais de 4 mil linhas que quando executado lia os dados de duas bases e gerava uma outra base com a informação das duas empresas, ou seja, Le os dados do Banco x e insere no banco y. Resultado, banco final do Grupo que comprou os bancos x e y.

Conheci profissionais acima da média. Tive contato com Diretores e Superintendentes que dava pra perceber fácil porque ocupavam estes cargos.

Entendi porque algumas pessoas ganham muito mais que as outras.

Frase de meu superior direto. – Precisamos conversar com a equipe, não possível. A impressão que tenho é que enquanto alguns estão na Formula1, outros estão no Parque do Hopi Hari.

Para trabalhar com clientes grandes, não tem jeito. Se você não documentar tudo, vai sofrer as conseqüências, e elas são severas.

Cuidado, existem mais pessoas interessadas em crescer a qualquer custo do que você pensa. Esteja sempre preparado.

Não pretendo sair do interior tão cedo. Não há dinheiro que pague o valor de uma vida com qualidade.

È galera comecei a escrever e vi que este post também foi mais pro lado pessoal do que eu pensava rs. Ainda tem muita coisa pra rolar e vou tentar escrever mais conforme as coisas vão surgindo, daí não esqueço de nada.

Falow

Obs.: Todos os fatos acima mencionados são meramente ficticios ou nunca aconteceram, ou não vão acontecer, ou não fui eu quem viu, ou me contaram, ou eu li, ou eu ouvi, resumindo: Se precisar, Eu nego!

June 30

Community Zone 2009

Galera,

Estou muito feliz em dizer que mais uma vez fui convidado para participar do Community Zone 2009, um evento para os profissionais que ajudam e influenciam na comunidade Microsoft.

Ano passado o evento foi bem legal e tive a oportunidade de passar alguns dias divertidos e produtivos com alguns camaradas e figuras do SQL Server Brasil. Espero que este ano seja tão bom quanto no ano passado... O futebol até as 2 da madruga no frio que tava, foi inesquecível... :-) .

A noite que teve o rodízio de Pizza também foi show demais... dei muita risada... até as piadas que rolavam eram sobre tecnologia huahuahuahaha, se alguém que não conhece informática entrasse na roda ia ficar boiando hahuahuhuauha....

Segue uma foto dessa noite:

clip_image002

A apresentação sobre como montar e apresentar uma palestra tbm foi muito boa...

Conhecer pessoalmente figuras como o Gustavo Maia, Luciano Caixeta, Laercio, Diego Nogare, Junior Galvão e tantos outros profissionais da Microsoft foi show...

Lembro que cheguei lá bem cedo, e fiquei lá, andando de um lado para o outro conhecendo o hotel e pensando. – Será que vou reconhecer alguém de alguma foto de blog ou mesmo dos fóruns? .... Daí vi o Maia e o reconheci da foto que ele havia colocado no MSDN Experience... Daí é daquele jeito, vc chega meio se jeito... – Ei você que é o Gustavo Maia? Hahaha....

No ano passado o evento foi em Bragança Paulista, esse ano ainda não sei onde vai ser. Espero que não seja muito longe pra que eu consiga ir.

Anyway, já esta na minha agenda, dias 28 e 29 de Agosto to por lá...

June 23

Fabiano VS Telefonica Parte 2

Depois de ler a seguinte noticia...

http://g1.globo.com/Noticias/Tecnologia/0,,MUL1203704-6174,00-TELEFONICA+VAI+SUSPENDER+VENDA+DE+SPEEDY+A+MEIANOITE+E+RECORRER+DE+DECISAO.html


Só tenho uma coisa a dizer!

Hhuahuahuahuahuhuahuahuauhauhuhauha.....
June 22

SQL Magazine edição nº 65

Galera finalmente o artigo que escrevi pra SQL Magazine foi publicado na edição deste mês.

clip_image002

Escrevi falando sobre o Query Processor e estamos com outro artigo de continuação no forno... aguardem pra ver...

Abraço

June 04

XBOX 360

Depois de ver o video no projeto da Microsoft chamado Natal for XBOX 360, só tenho uma coisa a dizer... PQP!!!!!!!!!!!!!
 
 
 
 
June 02

WebCast pra amanhã 03-06

Galera amanhã vou novamente ajudar o Luti na moderação(responder as perguntas...) de uma WebCast que ele vai apresentar pro MSDN.
 
Segue o link do post no blog dele com mais detalhes,
 
 
Essa vai ser imperdível. Nem preciso dizer que gosto muito do tema né?
 
Conto com a presença de todos..
 
Abraço.
 
May 18

WebCast SQL Server

Pessoal, na quarta-feira estarei ajudando o Luti na moderação de uma WebCast que ele vai apresentar.
 
Segue o link para inscrição e mais detalhes em relação ao tema.
 
 
Falow.
 
April 29

Produto Cartesiano e QO 2

Pessoal para quem achou interessante meu post sobre Produto Cartesiano e Query Optimizer, ontem o Craig escreveu um pouco sobre isso no blog dele, segue o link:

 

Implied Predicates and Query Hints

 

Abraço.

April 17

Material estudo, Query Processor

 
Atualizei meu SkyDrive com minha pasta de material para estudo do Query Processor.
 
Quem tiver interesse é só baixar..
 
 

Estudar SQL Server? Como começar? - 2

Lista de Feeds:

 

Troubleshooting Microsoft SQL Server
http://blogs.msdn.com/chrissk/rss.xml
SQL Server Premier Field Engineer Posts / Rants..
http://blogs.msdn.com/sachinp/rss.xml
PFE Brasil - SQL Server
http://blogs.msdn.com/pfebrasilsql/rss.xml
Microsoft SQL Server Native Client team blog
http://blogs.msdn.com/sqlnativeclient/rss.xml
Zen and the Art of SQL Server Maintenance
http://blogs.msdn.com/mwilmot/rss.xml
Meio Bit - Notícias, Dicas, Internet, Informática, Tecnologia, Download
http://feeds.feedburner.com/meiobit
SQLblog.com - The SQL Server blog spot on the web
http://sqlblog.com/blogs/MainFeed.aspx
Ken Henderson's WebLog
http://blogs.msdn.com/khen1234/rss.xml
Tips, Tricks, and Advice from the SQL Server Query Processing Team
http://blogs.msdn.com/sqlqueryprocessing/rss.xml
SQL Server , The BI Release
http://blogs.msdn.com/raulbalbuena/rss.xml
A SQL Server Blog
http://blogs.msdn.com/ashvinis/rss.xml
Bart Duncan's SQL Weblog
http://blogs.msdn.com/bartd/rss.xml
CREATE DATABASE
http://blogs.msdn.com/gauravbi/rss.xml
Craig Freedman's SQL Server Blog
http://blogs.msdn.com/craigfr/rss.xml
Conor vs. SQL
http://blogs.msdn.com/conor_cunningham_msft/rss.xml
Ian Jose's WebLog
http://blogs.msdn.com/ianjo/rss.xml
Ben Miller's World
http://dbaduck.com/feed/
Bill Ramos on SQL Server
http://blogs.msdn.com/billramo/rss.xml
Buck Woody - Database Administration - Carpe Datum
http://blogs.msdn.com/buckwoody/rss.xml
SQL, Analysis Services & related stories.
http://blogs.msdn.com/ikovalenko/rss.xml
Microsoft JobsBlog: Blog
http://feeds.feedburner.com/MicrosoftJobsBlog
CSS SQL Server Engineers
http://blogs.msdn.com/psssql/rss.xml
SQL Server Manageability Team Blog
http://blogs.msdn.com/sqlrem/rss.xml
Dan Guzman's Blog
http://weblogs.sqlteam.com/dang/Rss.aspx
SQL Server Security
http://blogs.msdn.com/sqlsecurity/rss.xml
SQL Bloke Blogs
http://www.sqlbloke.com/sql-bloke-blogs/rss.xml
Euan Garden's BLOG : SQL Server
http://blogs.msdn.com/euanga/rss.aspx?categoryid=7773
SQL Premier Field Engineering
http://blogs.msdn.com/menzos/rss.xml
rdoherty's WebLog
http://blogs.msdn.com/rdoherty/rss.xml
Notes from SQL Server Premier Field Engineer
http://blogs.msdn.com/sqlpfe/rss.xml
Database Underground | Sean McCown
http://weblog.infoworld.com/dbunderground/rss.xml
Zach Skyles Owens
http://blogs.msdn.com/zowens/rss.xml
Tibor Karaszi
http://sqlblog.com/blogs/tibor_karaszi/rss.aspx
Microsoft SQL Server Development Customer Advisory Team
http://blogs.msdn.com/sqlcat/rss.xml
Slava Oks's WebLog
http://blogs.msdn.com/slavao/rss.xml
Pedroso - SQL and Architecture Experience
http://blogs.msdn.com/pedroso/rss.xml
Microsoft SQL Server troubleshooting
http://blogs.msdn.com/joaol/rss.xml
Microsoft SQL ISV Program Management Team
http://blogs.msdn.com/mssqlisv/rss.xml
Brian Knight
http://pragmaticworks.com/community/blogs/brianknight/rss.aspx
Joe Sack's SQL Server WebLog
http://feeds.feedburner.com/JoeSacksSqlServerWeblog
SQL, .NET and everything Microsoft
http://blogs.msdn.com/sanchan/rss.xml
TSQL_language's WebLog
http://blogs.msdn.com/tsql_language/rss.xml
Sylvia's SQL Center
http://blogs.msdn.com/sylviav/rss.xml
SQLServerPedia
http://feeds2.feedburner.com/sqlserverpedia
Inglesonline
http://feeds.feedburner.com/InglsOnline
EXEC dbo.LongTermMemory__Archive
http://dis4ea.blogspot.com/feeds/posts/default
GuntherB's WebLog
http://blogs.msdn.com/guntherb/rss.xml
WesleyB's Blog
http://blogs.msdn.com/wesleyb/rss.xml
Tech Crumbs
http://blogs.msdn.com/rafats/rss.xml
TechNet Magazine RSS Feed:
http://technet.microsoft.com/pt-br/magazine/rss/default.aspx
The SQL Doctor is In (Real In)
http://drsql.spaces.live.com/feed.rss
SQL Server Perceptions
http://weblogs.sqlteam.com/dmauri/Rss.aspx
Don Kiely's Technical Blatherings
http://sqljunkies.com/WebLog/donkiely/rss.aspx
MohammedU's space
http://mohammedu.spaces.live.com/feed.rss
Chad Boyd - 2
http://blogs.mssqltips.com/blogs/chadboyd/rss.aspx
Tecla SAP
http://feeds.feedburner.com/teclasap
The Synchronizer
http://blogs.msdn.com/Synchronizer/rss.xml
Michael Rys
http://blogs.msdn.com/mrys/rss.xml
Elizabeth Vitt
http://www.sqlskills.com/blogs/liz/SyndicationService.asmx/GetRss
Herleson Pontes - IT Professional
http://herleson.spaces.live.com/feed.rss
Robson Brandão
http://rbtech.spaces.live.com/feed.rss
SQL in Stockholm
http://blogs.msdn.com/grahamk/rss.xml
Brent Ozar - SQL Server DBA
http://feeds.feedburner.com/BrentOzar-SqlServerDba
SQLSkills Complete Team Blog
http://pipes.yahoo.com/pipes/pipe.run?_id=vv9PBOp13BGAc67kLO2fWQ&_render=rss
SQL Server Performance
http://blogs.msdn.com/sqlperf/rss.xml
SQL Server Brasil
http://blogs.technet.com/sqlserverbrasil/rss.xml
Syscomments...
http://weblogs.sqlteam.com/dinakar/Rss.aspx
snaps & snippets
http://milambda.blogspot.com/feeds/posts/default
Wandenkolk & SQL Server
http://sqlwanden.blogspot.com/feeds/posts/default
Blog do Alexandre Lopes
http://arodrigueslopes.spaces.live.com/feed.rss
Learn English - EnglishPod
http://englishpod.com/lessons/feed/
Ramblings of a DBA
http://feeds.feedburner.com/RamblingsOfADba
Fabiano Neves Amorim - SQL Server
http://fabianosqlserver.spaces.live.com/feed.rss
Christian Bolton - SQL Server Blog
http://sqlblogcasts.com/blogs/christian/rss.aspx
Eladio Rincón
http://feedproxy.google.com/EladioRincon
Inside SQL Server
http://blogs.msdn.com/matt_hollingsworth/rss.xml
TechNet Radio
http://www.microsoft.com/winme/0512/25568/technet_radio_mp3.xml
Jamie's Junk
http://blogs.msdn.com/jamiemac/rss.xml
WinAjuda
http://feeds.feedburner.com/winajuda
Rafael Veronezi's Weblog
http://rveronezi.wordpress.com/feed/
SQL Server User Education
http://blogs.msdn.com/sqlserverue/rss.xml
SQLTeam.com Feed
http://feeds.sqlteam.com/Sqlteam
With CLUE as (Select * from Random_Thought ORDER BY Common_Sense DESC)
http://weblogs.sqlteam.com/geoffh/Rss.aspx
with (nolock)
http://withnolock.com/communityserver/blogs/MainFeed.aspx
Grumpy Old DBA
http://sqlblogcasts.com/blogs/grumpyolddba/rss.aspx
SQL Programmability & API Development Team Blog
http://blogs.msdn.com/sqlprogrammability/rss.xml
Rob Farley
http://feeds.feedburner.com/robfarley
Tony Rogerson's ramblings on SQL Server
http://sqlblogcasts.com/blogs/tonyrogerson/rss.aspx
SQL Server Storage Engine & Tools (SSQA.net)
http://sqlserver-qa.net/blogs/tools/rss.aspx
SQL Server: um Endpoint Brasileiro
http://blogs.msdn.com/procha/rss.xml
Sql Stuff
http://blogs.msdn.com/chadboyd/rss.xml
English Experts
http://feeds.feedburner.com/EnglishExperts
Microsoft Certifications
http://blogs.msdn.com/gerryo/rss.xml
Data Platform Insider
http://blogs.technet.com/dataplatforminsider/rss.xml
Eventos Microsoft
http://www.msdnbrasil.com.br/Microsoft.RSS/RssEventos.ashx?ds_publico=dese|arq&DS_TIPO_EVENTO=web%20cast%20on%20line
SQL Protocols
http://blogs.msdn.com/sql_protocols/rss.xml
MCDBA Brasil
http://www.mcdbabrasil.com.br/rss.php
SQL Server Engine Tips
http://blogs.msdn.com/sqltips/rss.xml
SimonS Blog on SQL Server Stuff
http://feeds.feedburner.com/SimonsSqlServerStuff
Aaron's space
http://vendoran.spaces.live.com/feed.rss
Inglês na Ponta da Língua
http://denilsodelima.blogspot.com/feeds/posts/default
Joe Webb
http://weblogs.sqlteam.com/joew/Rss.aspx
Glenn Berry's SQL Server Performance
http://glennberrysqlperformance.spaces.live.com/feed.rss
MVP Brasil
http://mvpbrasil.spaces.live.com/feed.rss
Michael Aspengren
http://blogs.msdn.com/spike/rss.xml
Microsoft Midwest District SQL Server News
http://blogs.msdn.com/dpaulson/rss.xml
SQL Server 2008 Application Compatibility Blog
http://blog.scalabilityexperts.com/feed/
LUTI @ Microsoft
http://blogs.msdn.com/luti/rss.xml
sqldbatips.com blog
http://sqlblogcasts.com/blogs/sqldbatips/rss.aspx
Running SAP Applications on SQL Server
http://blogs.msdn.com/saponsqlserver/rss.xml
Microsoft SQL Server Release Services
http://blogs.msdn.com/sqlreleaseservices/rss.xml
David Portas' Blog
http://blogs.conchango.com/davidportas/rss.aspx
SQL Server Compact - Compact & Capable
http://blogs.msdn.com/sqlservercompact/rss.xml
SQL Server 2008  (SSQA.net)
http://sqlserver-qa.net/blogs/sql2008/rss.aspx
The Premiers
http://sqlblogcasts.com/blogs/thepremiers/rss.aspx
Junior Galvão - MVP - SQL Server
http://juniorgalvao-mvp2007.spaces.live.com/feed.rss
Cihangir Biyikoglu - TSQLNet Weblog
http://blogs.msdn.com/cbiyikoglu/rss.xml
Vipul Shah's SQL Blogs
http://blogs.technet.com/vipulshah/rss.xml
Beatrice Nicolini
http://blogs.technet.com/beatrice/rss.xml
Shashank Pawar
http://blogs.technet.com/sqlman/rss.xml
Alexey Yeltsov
http://blogs.technet.com/sqlthoughts/rss.xml
Elisabeth Redei - Ex, SQL Server Support
http://sqlblog.com/blogs/elisabeth_redei/rss.aspx
Diego Nogare
http://diegonogare.spaces.live.com/feed.rss
Gustavo Maia Aguiar
http://gustavomaiaaguiar.spaces.live.com/feed.rss
Blog do Luti
http://feeds2.feedburner.com/luticm
SQL Server Storage Engine
http://blogs.msdn.com/sqlserverstorageengine/rss.xml
Tips, Tricks, and Advice from the SQL Server Query Optimization Team
http://blogs.msdn.com/queryoptteam/rss.xml

Estudar SQL Server? Como começar? - 1

Aproveitando a resposta de um e-mail que escrevi para um Amigo, vou colar aqui, segue:

Faaaala Fabiano blz cara?
Parabens pelo blog,tenho acompanhado ele e esta muito bom,eu gostaria depois de te mandar um artigo que o paralelismo é muito ruim..rsrsrs.....vou te provar que é ruim...quais que tem sido sua fonte de tunning? Deixa seu telefone depois para trocarmos umas figurinhas q q vc acha?
 
Att

 

Escrever no blog me ajuda MUITO a aprender, começar a escrever foi uma dica que peguei com o Luciano Caixeta Moreira, alias ele foi o cara que me incentivou em muita coisa, devo muito a ele. Depois de todas as ajudas que ele me deu, fiquei com uma pergunta na cabeça, “Meu, porque o Luciano está fazendo isso por mim? O que ele ganha com isso?” ... a resposta que vem em minha mente é, porque o cara é muito gente fina, não tem medo, nem o orgulho de ser “superior” aos outros.

 

Me manda o artigo sobre Paralelismo sim. Vou ler e mandar pro meu amigo Junior ele vai virar seu fã :-).

 

Sobre minhas fontes de Tunnig, se prepara porque eu aproveitei este e-mail para criar um post que fazia tempo que eu queria escrever.

 

O que eu faço para me manter atualizado, e aprender cada vez mais? Bom segue abaixo minha rotina de estudo, depois de ler você pode ser perguntar, “A mais ele não faz tudo isso”, sim eu faço.

 

Eu tenho lido MUITO coisa em blogs, no final deste post coloquei a lista com meus atuais RSSs. (Tive que colocar outro post, porque aqui na cabia)

Também não perco uma publicação dos artigos oficiais da Microsoft, já lançaram muita coisa boa, desde SQL 7.0 a 2008. Só por ai já tem coisa pra ler por 6 meses.

 

Sempre fico de olho nos posts de possíveis erros no site connect, leio sobre possíveis melhorias de tunning.

http://connect.microsoft.com/SQLServer

 

Baixo livros da Internet e leio capítulos que me interessam, outros leio inteiro. Compro livros, principalmente os que mais me interessam, por ex: os da Serie Internals da Denaley e os Training Kits.

 

Também vira e meche eu leio artigos MUITO técnicos, e excelentes do seguintes links:

http://research.microsoft.com/en-us/

http://portal.acm.org/dl.cfm

http://www.sigmod.org/sigmod/index.html

http://www.sqlpass.org/LearningCenter/TechnicalArticles.aspx

 

Também sou assinante da SQL Server Magazine americana, e da SQL Magazine brasileira, na brasileira, está pra sair um artigo que escrevi sobre Query Processor. Espero que este mês finalmente saia a publicação(já fechamos o artigo faz uns 3 meses).

 

Também recebo e-mails de News dos seguintes sites:

http://www.sqlteam.com/

http://www.sqlservercentral.com/

http://www.sql-server-performance.com/

http://www.jumpstarttv.com

http://searchsqlserver.techtarget.com/

http://www.linhadecodigo.com.br/

http://www.imasters.com.br/

 

Também sempre tento assistir as WebCasts que tem por ai, seja da Quest, Idera, Microsoft. Tento ouvir PodCasts, RadioCasts, chats e entrevistas online. Procuro por eventos online, e vídeos de gravações de eventos. Tento achar vídeos sobre o assunto que estou querendo saber mais.

 

Fora isso, tento me manter o mais próximo possível dos fóruns MSDN e TechNet, aprendo muita coisa lá.

 

Quando tenho alguma dúvida em relação a algum problema interno do SQL, e não acho muita referência na internet, entro em contato direto com “os caras” da Microsoft.

 

Meu principal contato é o Conor, posso considerá-lo como meu mentor em SQL Server, o cara é gente finíssima, espero conhecê-lo pessoalmente em breve.

Conor Cunningham - Architect no Query Processor Team

 

Todos estes outros abaixo eu já troquei e-mail, e você pode estar pensando, e eles respondem? Sim, eles respondem. Claro que eu não fico pentelhando e abusando, com perguntas estúpidas. Mas sempre que preciso eles estão lá pra me dar um help.

 

Na lista abaixo, tem de tudo, PHDs formados em Harvard, MVPs e etc... só a “nata”.

 

Craig Freedman - SQL Engine

Bart Duncan - SQL Manageability Team

Cesar Galindo-Legaria - Development Lead

Boris Baryshnikov - SQL Engine

Surajit Chaudhuri - Principal Researcher

Kalen Delaney - Dispensa comentários...

Paul S. Randal - Dispensa comentários...

Kimberly L. Tripp - Dispensa comentários...

Luciano Moreira - Ex MS, Especialista em Desenvolvimento em SQL Server

Buck Woody - Program Manager

Eric Kang - SQL Developer, Escreveu a funcionalidade de Debug no SQL 2008

Richard Waymire - SQL Developer

Michael Rys - XML no SQL? é com ele.

Trika Harms zum Spreckel - Certificações

Gerry O'Brien - Certificações

Christian Kleinerman - SQL Engine

Jacob Sebastian - MVP SQL


April 16

Como remover uso de cursores, utilizando CTEs

Galera, vou publicar um e-mail que na época mandei apenas para o pessoal daqui da empresa, talvez a informação seja útil pra vocês.

-----------------------------

Pessoal a fim de informação segue uma dica de como transformar isso:

clip_image002

Nisso:

clip_image004

Sem usar cursor

DECLARE @Tab TABLE(Val_Min Int, Val_Max Int)

INSERT INTO @Tab(Val_Min, Val_Max) VALUES(1,3)

INSERT INTO @Tab(Val_Min, Val_Max) VALUES(15,20);

INSERT INTO @Tab(Val_Min, Val_Max) VALUES(6,9);

SELECT * FROM @TAB

-- Cria tabela sequencial que vai de 1 a 100, pode ser qualquer tipo de tabela, neste caso usei a

-- funcionalidade de CTE.

WITH Sequencial AS(

SELECT 1 as ID

UNION ALL

SELECT ID + 1

FROM Sequencial

WHERE ID < 100)

-- Retorna os dados

SELECT Val_Min, Val_Max, ID

FROM @TAB a

INNER JOIN Sequencial s

ON s.ID >= a.Val_Min

AND s.ID <= a.Val_Max

ORDER BY a.Val_Min, a.Val_Max, s.ID

Esta tabela auxiliar que vai de 1 a 100, serve para bastante coisa.

Aproveito para refazer o convite de cadastrarem meu blog no RSS de seu outlook. Normalmente dicas como essa coloco lá, assim só lê quem tiver interesse.

Segue o link http://fabianosqlserver.spaces.live.com/feed.rss

É só cadastrar em Ferramentas\Configurações de Conta\RSS Feeds\

March 26

Produto Cartesiano e Query Optimizer

Galera, existem algumas situações onde o QO(Query Optimizer) simplesmente, decide remover uma instrução do join de uma consulta o que acaba gerando um inesperado Produto Cartesiano, ou seja, a mesma coisa que um join sem relacionamento, um cross join.

 

Por exemplo, imagine o seguinte código:

 

use tempdb

GO

 

declare @tab1 Table(a Int)

 

insert into @tab1

select TOP 1000 1

  from sysobjects b, sysobjects a

 

set statistics io on

set statistics time on

 

select * from @tab1 a

 inner join @tab1 b

    on a.a = b.a

 

select * from @tab1 a

 inner join @tab1 b

    on a.a = b.a

 where a.a = 1

 

set statistics io off

set statistics time off

 

A duas consultas acima retornam todos os registros ta tabela @tab1, mas existe uma grande diferença entre a primeira e a segunda consulta.

 

A primeira diferença que podemos notar é que a segunda consulta contem uma condição no where onde a.a tem que ser igual a 1. Ai é que ta, neste caso o QO sabe que existe uma redundância de comparação, pois se “a.a” é igual 1(where), e “a.a” é igual a “b.a” (join), logo ele sabe que b.a também será igual a 1. Portanto neste caso ele remove a condição do join (a.a = b.a) e aplica o filtro de “a = 1” nas tabelas “a” e “b”.

 

Este comportamento pode ser evidenciado ao analisarmos os planos de execução gerados. O plano da segunda consulta ficou assim:

 

StmtText Argument
select * from @tab1 a   inner join @tab1 b      on a.a = b.a   where a.a = 1 NULL
  |--Nested Loops(Inner Join) NULL
       |--Table Scan(OBJECT:(@tab1 AS [b]), WHERE:(@tab1.[a] as [b].[a]=(1))) OBJECT:(@tab1 AS [b]), WHERE:(@tab1.[a] as [b].[a]=(1))
       |--Table Scan(OBJECT:(@tab1 AS [a]), WHERE:(@tab1.[a] as [a].[a]=(1))) OBJECT:(@tab1 AS [a]), WHERE:(@tab1.[a] as [a].[a]=(1))

 

Repare que na coluna argument o QO gerou apenas um argumento para a leitura das tabelas, e no Loop ele não gerou a condição de join. Isso caracteriza um Produto Cartesiano, onde para cada linha da tabela definida como “a”, o SQL vai ligar com todas as linhas da tabela “b”.

 

Ok, mas isso é ruim?... Sim neste caso sim... Pois para esta consulta utilizar um algoritmo de Hash para fazer o join seria muito mais eficaz. Para confirmar isso, basta verificar o plano gerado pela primeira consulta. Lembrando que ambas as consultas são relativamente iguais. Repare que o SQL gerou um Hash Join para fazer a ligação entre as tabelas.

 

StmtText

Argument

select * from @tab1 a   inner join @tab1 b      on a.a = b.a

NULL

  |--Hash Match(Inner Join, HASH:([b].[a])=([a].[a]), RESIDUAL:(@tab1.[a] as [b].[a]=@tab1.[a] as [a].[a]))

HASH:([b].[a])=([a].[a]), RESIDUAL:(@tab1.[a] as [b].[a]=@tab1.[a] as [a].[a])

       |--Table Scan(OBJECT:(@tab1 AS [b]))

OBJECT:(@tab1 AS [b])

       |--Table Scan(OBJECT:(@tab1 AS [a]))

OBJECT:(@tab1 AS [a])

 

Se analisarmos os resultados do statistics io e statistics time, veremos que a primeira consulta, utilizou menos tempo, IO e CPU para retornar os dados.

 

Primeira consulta (Hash Join):

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table '#2E75B1C0'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 

SQL Server Execution Times:

   CPU time = 328 ms,  elapsed time = 19976 ms.

 

 

Segunda consulta (Loop Join):

Table '#2E75B1C0'. Scan count 2, logical reads 2002, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 

SQL Server Execution Times:

   CPU time = 407 ms,  elapsed time = 20377 ms.

 

Bom, mas você pode estar pensando, bem, neste caso é só utilizar um hint para forçar o uso do Hash Join certo? Errado, se você tentar fazer isso vai receber a seguinte mensagem:

 

select * from @tab1 a

 inner join @tab1 b

    on a.a = b.a

 where a.a = 1

option(hash join)

 

Msg 8622, Level 16, State 1, Line 20

Query processor could not produce a query plan because of the hints defined in this query. Resubmit the query without specifying any hints and without using SET FORCEPLAN.

 

Como o SQL remove a condição do Join, ele terá que fazer um Produto Cartesiano e o SQL só consegue fazer isso utilizando o Loop Join L. Neste caso, o Hint colide com a Lógica do QO e gera o erro.

 

Como resolver o problema?....

Basta esperar a próxima versão do SQL, e torcer para que eles copiem o Oracle, que neste caso criou um parâmetro para tratar com este problema.

http://jonathanlewis.wordpress.com/2006/12/13/cartesian-merge-join/

 

Enviei este exemplo para o Boris Baryshnikov (SQL Server Engine), e ele me respondeu dizendo que estão trabalhando em uma correção para uma futura release.

 

Já existe um chamado no Connect falando sobre isso, portanto, só nos resta aguardar, e ficarmos atentos a este problema...

March 19

Fabiano VS Telefônica

Depois de 4 meses utilizando E PAGANDO meu speedy de 2 megas(isso mesmo no plural, conforme a Senhora Marcia escreveu abaixo), cansei de pagar o valor indevido e pedi o cancelamento.

 

Quero deixar aqui meu desprazer com a péssima qualidade de serviços prestados pela Telefônica. E nem ao menos português eles sabem, pelos menos usa um corretor automático e pronto.

 

Marcia Augusto: Bem Vindo(a) Fabiano, em que posso ajudar ?

Fabiano:              Olá Marcia

Fabiano:              Quero trocar meu Speedy de 2 mb para 1 mb

Fabiano:              você pode fazer isso?

Fabiano:              ?

Fabiano:              ?

Fabiano:              Tem alguém ai?

Marcia Augusto: Senhor Fabiano por gentileza entre em contato no chat relacionado a vendas, esse se refere-se ao cancelamento.

Fabiano:              Ok, então cancele o meu Speedy

Marcia Augusto: Senhor. ! Para melhor atendê-lo por gentileza informe nome completo e telefone com ddd do assinante da linha telefônica.

Fabiano:              Fabiano Neves Amorim, 014-xxxxxxxxx

Fabiano:              Cancelou?

Fabiano:              ?

Marcia Augusto: Para realizar o cancelamento do serviço soeedy é necessário a confirmação do número de CPF e RG do assinante da linha.

Fabiano:              CPF: xxxxxxx RG: xxxxxxx

Marcia Augusto: Aguarde um momento para verificação de seu cadastro.

Fabiano:              ok

Fabiano:              ok

Marcia Augusto: Aguarde um momento para verificação em nosso sistema.

Fabiano:              ok

Marcia Augusto: Por gentileza aguarde mais um momento.

Fabiano:              ok

Marcia Augusto: Qual motivo da solicitação do cancelamento?

Fabiano:              Já fazem 4 meses que você estão me enviando a conta com o valor errado. Cansei de tentar reclamar, portanto cancele.

Marcia Augusto: Senhor Fabiano o senhor está no período de fidelidade se cancelar vai gerar quebra de fidelidade no valor de 259,20.

Fabiano:              Mas vocês não estão me cobrando o valor correto, portanto não existe “fidelidade” nenhuma entre as partes.

Marcia Augusto: Senhor conforme verificado no sistema o senhor está no período de fidelidade.

Marcia Augusto: Em relação as contas peço por gentileza que peça uma análise das contas.

Fabiano:              Ja pedi

Fabiano:              Veio dizendo que não havia nenhum erro.

Marcia Augusto: Senhor Fabiano o seu speedy é de 1 mega .

Fabiano:              E qual é o valor correto?

Marcia Augusto: Senhor Fabiano seu speedy é de 2 megas. desconsidere essa primeira informação.

Fabiano:              Da mensalidade?

Marcia Augusto: Senhor peço por gentileza que aguarde mais um momento para que eu possa verificar no sistema.

Fabiano:              ok

Marcia Augusto: Por gentileza aguarde só mais um momento, pois nosso sistema se encontra lento.

Fabiano:              ok

Marcia Augusto: Senhor Fabiano obrigado por esperar , o valor do speedy é de 99;87.

Fabiano:              pois é, não foi este valor o acordado

Fabiano:              durante a compra, ...

Fabiano:              Faz o seguinte... cancela

Fabiano:              Eu pago a Multa e nunca mais falo com a Telefonica e todos ficamos felizes

Marcia Augusto: Senhor se cancelar vai gerar quebra de fidelidade no valor de 259,20,mesmo assim o senhor quer cancelar?

Fabiano:              CANCELA

Marcia Augusto: Aguarde um momento enquanto efetuo seu pedido e emito seu protocolo.

Marcia Augusto: Senhor Fabiano por gentileza anote o número do protocolo N1090319975.

Marcia Augusto: O prazo para ser retirado o serviço é de sete dias úteis para sair do sistema.

Fabiano:              E quando chega a conta com a "quebra" de fidelidade?

Marcia Augusto: O senhor deseja mais alguma informação?

Fabiano:              E quando chega a conta com a "quebra" de fidelidade?

Marcia Augusto: Provavelmente será na próxima fatura.

Marcia Augusto: Algo mais que posso ajuda-lo?

Fabiano:              Consegue cancelar a linha telefonica?

Marcia Augusto: Senhor Fabiano nese momento não da porque fica pedente a ordem de cancelamento do serviço speedy só depois de sete dias.

Marcia Augusto: Para melhor atendê-lo por gentileza informe nome completo e telefone com ddd do assinante da linha telefônica.

Marcia Augusto: Desconsidere essa informação senhor Fabiano.

Fabiano:              Ok, consegue cancelar ou não?

Marcia Augusto: Senhor Felipe agora o sistema não permite com já disse, a ordem fica pendente no sistema só depois de sete dias..

Fabiano:                Ok então só daqui a 7 dias úteis correto? só para constar meu nome é Fabiano e não Felipe.

Marcia Augusto: Sim senhor Fabiano.

Marcia Augusto: Foi um prazer atende-lo. A telefônica agradece ,tenha uma boa tarde.

Fabiano:                 Muito obrigado, sou eu quem agradeço a gentileza da senhora.

Marcia Augusto: Aguarde um momento para verificação em nosso sistema.

Marcia Augusto: Por gentileza desconsidere a mensagem acima pois as informações estão divergentes de acordo com o que foi solicitado.

 


Pois é pessoal, espero do fundo do coração e alma, que um dia esse nosso Brasil e nossos governantes tenham a coragem de pensar pelo menos um pouco, só um pouco, no povo.

March 15

Entrevista - Eu mesmo :-)

Galera, como devem ter percebido nestas ultimas semanas estou um pouco distante dos fóruns e do Blog.

Estou trabalhando em um projeto de integração tecnológica entre 2 grandes instituições financeiras. Ainda não sei se posso dar mais detalhes portanto, por enquanto fica assim...

Como o projeto é bem grande, com certeza durante o andamento das fases do projeto, surgirão vários assuntos interessantes para compartilhar com vocês.

Prometo que assim que eu puder posto mais detalhes...

 

Por enquanto fiquem com a entrevista que a um tempo atrás, a pedido do Diego Nogare, eu mesmo respondi. As perguntas são as mesmas que fiz com alguns profissionais SQL Server.

 

Eu acho que não coloquei aqui no blog minhas respostas portanto... segue para quem não viu na revista.

 

1.       Vamos começar falando da novidade do momento, quais as novas features do SQL Server 2008 que você acha mais importante, e porque? Nomeie pelo menos 3.

a.       A que me fez parar e dizer UAU foram as implementações de Compression, Page Compression, Row Compression e Backup Compression, fiz alguns testes e me surpreendi com a qualidade de compressão de dados. Usei uma frase na WebCast de “Caminhos de Upgrade para SQL Server 2008”, - Imagina converter um livro de 1000 páginas para apenas 200, pois é mais ou menos isso que o algoritmo de compressão por página LZ78 criado pelos geeks seniors Lempel e Ziv faz.

1.       Nos meus testes cheguei a seguinte conclusão.

Tabela

CPU

Writes

Duration

Tamanho

Pages

Tmp_Row_Compression

10656

1617

45809

12 MB

1613

Tmp_Page_Compression

11359

1142

44118

8 MB

1133

Tmp_Sem_Compression

10032

5914

46873

46 MB

5883

 

b.      Filtered Index – Essa veio bem a calhar, poder escrever um comando desses vai ajudar e muito para quem tem tabelas muito grandes e com acesso a dados mais recentes, caso partition não for uma possibilidade, imagine o seguinte poderíamos criar um índice para cada período e gravar cada índice em um filegroup diferente que por sua vez estará em discos diferentes. Interesting... vale a pena estudar a fundo essa feature.

c.       Resource Governor – Esse pode ser utilizado tanto em ambientes de produção como ambientes de teste, imagine o seguinte cenário(bem comum em desenvolvedoras de Software), Um servidor SQL Server distribuído para todos os desenvolvedores utilizarem para testes, desenvolvimento etc... Em um banco desses rola de tudo, select *, operações bulk insert, restore de backup, tudo ao mesmo tempo e sempre tem aqueles “comilões” de recurso que rodam tudo isso ao mesmo tempo J(eu não) , com o Resoruce Governor poderíamos limitar a quantidade de CPU e memória para que ele não pare o servidor enquanto trabalha.

2.       Em relação a performance no SQL Server 2005, quais as features você acha mais importante?

a.       O SQL 2005 comparado com o 2000, tem muitas, mas posso destacar a partition como uma excelente escolha para balanceamento de carga entre servidores diferentes, procure por Distributed Partitioned Views / Federatad Databases.

3.       Quais suas dicas para um profissional que está iniciando em SQL Server?

a.       Estudar muito e manter-se atualizado, se puder comece com um bom curso oficial Microsoft, caso não seja possível fazer o curso, existem MUITOS blogs e sites especializados em SQL Server que na minha opinião tem um conteúdo até melhor e mais aprofundado em cada tecnologia do SQL.

4.       O que é necessário para se tornar um usuário Master em SQL Server?

a.       Eu acho que somente com experiência e uma vivência diária de trabalho com o SQL Server o usuário poderá um dia dizer que é um Master em SQL Server. Mesmo assim tenho certeza que haverão situações em que até mesmo um super usuário terá que recorrer ao velho e bom senhor do conhecimento, “Pai-Google”.

5.       O que é necessário para se tornar um usuário Master em Transact SQL Server?

a.       Encontre uma empresa que tem um banco de dados com mais de 2 mil procedures e 3 mil functions e tabelas com mais de 200 milhões de registros e comece a tentar otimizar os códigos TSQL. Acredite ou não isso é MUITO comum de se encontrar, já trabalhei em algumas implementações de DW em diversos banco de dados e já vi alguns desses bancos. Caso não seja possível faça o seguinte, inicie um trace no profiler e abra a aplicação que roda no banco, comece dar os cliques e fazer as operações comuns do dia a dia dos usuários do software e depois veja os selects executados por sua aplicação e tente otimizá-los.

6.       Qual sua opinião em relação ao uso excessivo de Triggers no banco de dados?

a.       Eu não sou contra o uso de triggers mas tento evitá-las o máximo possível, na minha opinião elas só deixam o código mais complexo e mais pesado. Eu conversei com o Conor Cunningham(Super Plus Master Boss do time do Query Processor) sobre triggers. Vou deixar 2 links para meus posts falando Sobre Triggers.

1.       Why triggers are Bad - Part I

1.       http://fabianosqlserver.spaces.live.com/Blog/cns!52EFF7477E74CAA6!486.entry

2.       Why triggers are Bad - Part II

1.       http://fabianosqlserver.spaces.live.com/Blog/cns!52EFF7477E74CAA6!488.entry

7.       Qual o maior erro que uma pessoa pode cometer ao analisar um plano de execução?

a.       Sem dúvida é achar que um Index Seek é SEMPRE melhor que um Clustered Index Sacan. Ou então ver uma flecha indicando o uso de paralelismo e logo voltar no código para incluir um OPTION(MAXDOP 1).

8.       Quando usar um Clustered Index e quando usar um Non Clustered Index?

a.       Isso depende bastante de cada cenário, mas eu particularmente uso Int IDENTITY(1,1) para pks e deixo ela como meu índice cluster e os nonclustered para consultas onde poderei fazer um covered índex, onde o SQL terá que acessar apenas o nonclustered índex para ler toda as informações necessárias para retornar os dados da consulta.

9.       Porque estatísticas são importantes?

a.       Estatísticas estão a toda hora sendo utilizadas pelo query processor para conseguir gerar o melhor plano de execução para sua consulta. Por exemplo nas estatísticas ele poderá saber se o valor que você está procurando irá retornar 10 linhas ou então 10 milhões de linhas, neste caso ele poderia optar por usar paralelismo por ex.

10.   O quanto fragmentação no banco de dados pode afetar performance? Existe algum beneficio em ter fragmentação no banco?

a.       Physical fragmentation é quando você tem espaço livre nas páginas da tabela e isso em alguns casos pode ser uma coisa boa, já que irá evitar que o SQL efetue splits em futuros inserts e updates na tabela.

b.      Logical fragmentation é quando a próxima página lógica não é contínua... Ou seja, o SQL não irá conseguir fazer um read-ahead o que sempre será ruim. Confesso que fiquei curioso em relação a algum cenário onde esse tipo de fragmentação seria uma coisa boa, entrei em contato com nada mais nada menos que a Kimberly Trip e para minha surpresa após 1 hora que eu havia enviado o e-mail ela me respondeu dizendo que ela não via nenhum cenário onde esse tipo de fragmentação poderia ser benéfica, e mais, ela respondeu com cópia para o Paul Randal perguntando a opinião dele e logo depois ele também respondeu dizendo a mesma coisa. Portanto me fiz por satisfeito com as respostas J.

11.   Afinal paralelismo é bom ou ruim?

a.       Na minha opinião Paralelismo é bom. O que acontece é que em alguns casos onde temos uma pressão de CPU no servidor e o SQL optou por por fazer uma determinada consulta utilizando paralelismo, depois disso, o servidor recebeu outras requisições que demandavam muito mais CPU, neste caso a coisa pode ficar feia. L

12.   Você utiliza alguma ferramenta para auxiliar na resolução de problemas de performance? Quais?

a.       Profiler e SSMS são minha prediletas, as ferramentas de gerenciamento da Idera e da Quest são muito boas, mas é difícil convencer alguém de que o alto custo delas vale a pena.

13.   Em um banco de dados em produção você utiliza algum TraceFlag habilitado?

a.       Sim o 1118 para que o SQL não aloque mais extends mistos e sempre aloque extends uniformes, evitando uma possível contenção na TempDB que na teoria é a maior utilizada pela controladora SGAM já que as tabelas temporárias casualmente são pequenas.

14.   Cite 3 livros que não podem faltar na coleção de um especialista SQL Server.

a.       Inside SQL Server 2000 e todos da Série Inside Microsoft SQL Server 2005.

 

15.   Nestes anos de experiência, Qual foi o problema mais difícil de resolver que encontrou?

a.       Com certeza foi na otimização de uma proc com 2500 linhas que como vocês podem imaginar efetuava vários processos super complexos, depois de muito brigar com ela, mudei bastante coisa e no fim deu tudo certo J.

 

16.   Já passou por algum daqueles problemas que resolveu mas até hoje não sabe o que era?

a.       Direto, e quanto acontece isso faço o seguinte, para tudo, fecha, apaga e começa novamente, sempre deu certo, mas não me pergunte qual era o problema.

 

17.   Qual o maior banco de dados que já trabalhou e quantas linhas tinha a maior tabela que já viu?

a.       O banco de dados de um de nossos clientes, 200 gb e tabelas com mais de 250 milhões de registros, punk. Tem noção do tempo que demora pra reindexar ela?

18.   Como diria o Tobby(charges.com.br) - Bate bola jogo rápido:

a.       Um concorrente digno do SQL Server: Oracle para Grandes BDs, Firebird contra a Versão Express.

b.      Uma feature: Compression.

19.   Um comando SQL(o meu predileto é o SHUTDOWN WITH NOWAIT J) : SHUTDOWN WITH NOWAIT

20.   Você tem algum blog? Site? Msn?... Como os usuários da comunidade podem entrar em contato com você?

a.       E-Mail: fabiano_amorim@bol.com.br

b.      Blog: http://fabianosqlserver.spaces.live.com/blog/

c.       Msn: fabianonevesamorim@hotmail.com

21.   Deseja deixar alguma consideração final?

a.       “É melhor ser criticado pelos sábios do que ser elogiado pelos insensatos. Elogios vazios são como gravetos atirados em uma fogueira.” Eclesiastes.

 
February 20

Parameters and Stored Procedures

Semana passada eu escrevi um post rápido falando sobre um problema de performance que ocorreu em um de nossos clientes.

Vamos entender direito o problema para caso vocês passem por isso, saibam como evitar, ou como investigar o que está acontecendo.

Um pouco de “Parameter Sniifing”

Antes de começar com o código deixa eu explicar uma coisa,

Sempre que uma procedure é executada, e o Query Processor não encontra um plano de execução no Cache, ele da inicio a uma sério de passos que irão gerar um plano de execução para a consulta. Sabemos que uma procedure contem vários comandos e cada um deles tem o seu plano de execução. Estes planos são gerados durante a execução da consulta, ou seja, durante a execução do batch, na fase de compilação da proc. Ao efetuar um exec proc... o SQL gera o plano de todos os comandos de dentro do batch de uma só vez. Com os planos gerados, o Query Execution Engine vai executando os planos.

Para estimar a cardinalidade das consultas de dentro da proc, o QO(Query Optimizer) executa um processo chamado de Sniffing, ou seja, ele lê os valores dos parâmetros de entrada da proc e utiliza estes valores para fazer a estimativa. Esta estimativa é extremamente importante pois uma má estimativa pode gerar planos de execução ineficientes(como veremos mais abaixo).

Veja bem, eu já vi pessoas dizendo que Parameter Sniffing é um problema, na verdade ele pode causar problemas, mas geralmente é um excelente recurso. Veremos 2 tipos de problemas que podem ser causados por causa de um “Bad Sniffing” J.

Quando o Sniffing funciona

Vamos imaginar a seguinte proc:

   1:  CREATE PROCEDURE st_proc @Valor Int
   2:  AS
   3:  SELECT *
   4:  FROM TabTeste
   5:  WHERE Valor <= @Valor

Ao executar esta proc, se o valor passado para a variável @Valor for altamente seletivo, ou seja, irá fazer com que a consulta retorne poucas linhas, então é bem provável que o SQL utilize um possível índice na coluna valor e depois faça um bookmark para ler os dados que não estão no índice.

Bom, mas em tempo de compilação(geração do plano) da proc, como o SQL sabe se o valor é bastante seletivo ou não?. Ele lê (sniff) o valor de @Valor e usa este valor para ver a seletividade e cardinalidade nas estatísticas do índice.

Tendo o valor para ser analisado nas estatísticas o SQL pode gerar o plano mais adequado conforme este valor.

Quando o Sniffing não funciona 1

Vamos imaginar a seguinte proc:

   1:  CREATE PROCEDURE st_proc @Valor Int
   2:  AS
   3:  DECLARE @Variavel_Auxiliar Int
   4:  SET @Variavel_Auxiliar = @Valor;
   5:  SELECT *
   6:  FROM TabTeste
   7:  WHERE Valor <= @Variavel_Auxiliar

Quando utilizamos variáveis auxiliares nas procs, em tempo de compilação, o SQL não consegue estimar qual será o valor da variável @Variavel_Auxiliar, portanto ele não tem como fazer as estimativas necessárias para decidir qual plano gerar. No tópico 5 deste post, eu já falei o que o SQL faz quando ele não consegue estimar a cardinalidade de um valor.

Se ele não consegue estimar ele vai, “chutar”, neste caso(sinal de <=) a estimativa será de 30% do tamanho da tabela. E posso te garantir que com uma estimativa de 30% da tabela, com certeza o SQL não vai gerar um BookMark, pois com esta estimativa é mais performático fazer um Scan. Mesmo que este Scan seja para ler apenas 1 linha. Lembre-se que o SQL não sabe que é só 1 linha que será retornada, para ele, será retornada 30% da tabela.

Quando o Sniffing não funciona 2

Vamos imaginar a seguinte proc,

   1:  CREATE PROCEDURE st_proc @Valor Int
   2:  AS
   3:  IF @Valor = 0
   4:  SET @Valor = 10;
   5:  SELECT *
   6:  FROM TabTeste
   7:  WHERE Valor <= @Valor

Este foi o problema que aconteceu com nosso cliente. Havia uma procedure onde o valor do parâmetro de entrada era alterado durante a execução da proc. Se a chamada da procedure fosse @Valor = 0, então o valor seria alterado para 10 fazendo com que a estimativa inicial utilizada pelo SQL Server ficasse incorreta.

Independente de o valor do parâmetro de entrada ser alterado, para a compilação da procedure, o SQL vai utilizar o valor recebido inicialmente, ou seja, o valor informado na execução da procedure. Se eu passar o valor 0, o SQL vai usar este valor para estimar a cardinalidade da coluna. Digamos que esta consulta resulta em uma estimativa de retorno de apenas 1 linha, e o SQL decide utilizar um índice pela coluna valor mais um bookmark. Porem com a alteração do parâmetro a consulta passará a retornar 1000 linhas. Neste cenário teríamos um péssimo plano.

Exemplificando

Para exemplificar os problemas mencionados acima, criei uma tabela chamada TabTeste, com um índice nonclustered na coluna Valor e uma proc que faz alguns selects nesta tabela.

Nesta proc, temos os 3 casos mencionados acima, onde a 1º consulta faz a estimativa correta, a segunda consulta utiliza a variável auxiliar e por fim uma consulta que faz um select utilizando a variável após sofrer uma alteração.

   1:  USE TEMPDB
   2:  GO
   3:  SET NOCOUNT ON;
   4:   
   5:  IF OBJECT_ID('tempdb.dbo.TabTeste') IS NOT NULL
   6:    DROP TABLE TabTeste
   7:  GO
   8:  IF OBJECT_ID('tempdb.dbo.st_Proc_Teste') IS NOT NULL
   9:    DROP PROC st_Proc_Teste
  10:  GO
  11:  CREATE TABLE TabTeste(ID Int Identity(1,1) Primary Key,
  12:                                            Nome VarChar(200) NOT NULL,
  13:                                            Valor Int NOT NULL)
  14:  GO
  15:  DECLARE @i INT
  16:  SET @i = 0 
  17:  WHILE (@i < 50000)
  18:  BEGIN
  19:    INSERT INTO TabTeste(Nome, Valor)
  20:    VALUES(NEWID(), ABS(CHECKSUM(NEWID()) / 1000000) + 1)
  21:    SET @i = @i + 1 
  22:  END;
  23:  GO
  24:  INSERT INTO TabTeste(Nome, Valor) VALUES(NEWID(), 0)
  25:  INSERT INTO TabTeste(Nome, Valor) VALUES(NEWID(), 0)
  26:  INSERT INTO TabTeste(Nome, Valor) VALUES(NEWID(), 0)
  27:  GO
  28:  CREATE NONCLUSTERED INDEX IX_Index ON TabTeste(Valor);
  29:  GO
  30:  CREATE PROCEDURE dbo.st_Proc_Teste @Valor Int
  31:  AS
  32:  BEGIN
  33:    DECLARE @Variavel_Auxiliar Int
  34:    SELECT @Variavel_Auxiliar = @Valor;
  35:    -- Variável original sem alterar
  36:    SELECT *
  37:    FROM TabTeste
  38:    WHERE Valor <= @Valor
  39:    -- Variável auxiliar
  40:    SELECT *
  41:    FROM TabTeste
  42:    WHERE Valor <= @Variavel_Auxiliar
  43:    IF @Valor = 0
  44:    SET @Valor = 10;
  45:    -- Variável original alterada
  46:    SELECT *
  47:    FROM TabTeste
  48:    WHERE Valor <= @Valor
  49:  END

Vamos executar a proc e visualizar os dados retornados.

EXEC dbo.st_Proc_Teste @Valor = 0

Para as consulta 1 e 2 podemos observar que são retornadas apenas 3 linhas, já que na tabela TabTeste só existem 3 valores onde o valor da coluna “Valor” seja menor ou igual a 0. Já na terceira consulta, o valor utilizado no where foi o valor “10”, já que ele foi alterado em tempo de execução. Neste caso várias linhas serão retornadas. Não apenas 3.

Para as consultas 1 e 2, com certeza fazer utilizar o índice nonclustered e fazer um Bookmark é a melhor opção de acesso aos dados, já para a 3º consulta é bem provável que o ideal seria fazer um Scan já que vários registros serão retornados.

Vamos ver o que aconteceu:

Figura - 1º Plano

Podemos observar que a estimativa de quantidade de linhas que seriam retornadas foi precisa, já foi estimado 3 e o número atual de linhas retornadas também foi 3. Aqui podemos ver que o Sniff foi de grande valor.

Figura - 2º Plano

Aqui já podemos ver que o SQL não utilizou o índice, e sim gerou um Clustered Index Scan, mas porque ele não utilizou o Índice? Bom, a resposta está facil, ele gerou uma estimativa incorreta. Como utilizamos a variável auxiliar o SQL estimou que 30% da tabela ou seja, 15000 linhas seriam retornadas, e para retornar 15 mil linhas compensaria fazer o Scan. Mas podemos observar que a quantidade de linhas atuais é de apenas 3.

Figura - 3º Plano

Já o 3º plano utilizou o Índice gerando assim um Idex Seek, mas perai. Quantas linhas ele estimou? Apenas 3. E quantas foram retornadas? 226. Com certeza neste caso seria melhor ele gerar um Scan do que fazer o Seek + Bookmark.

Ora, mas porque ele gerou o bookmark, isso porque para fazer a estimativa, ele utilizou o valor passado no parâmetro de entrada.

Statistics IO

Para comprovar que o 2º e 3º plano geraram planos incorretos, basta analisarmos a quantidade de IOs gerados para retornar os dados de cada consulta.

Nas consultas 2 e 3, o número de IOs foi bem alto. O número de IOs efetuados pela consulta 2 deveria ser igual ao número da consulta 1, já que ambas retornam os mesmo registros.

Para confirmar se na consulta 3 realmente compensava fazer um Scan ao invéz de um Seek + BookMark, podemos simplesmente olhar quantos IOs foram necessários para fazer um Scan na tabela(consulta 2).

Visualizando os valores utilizados pelos parâmetros

Para confirmar quais valores foram utilizados nas consultas, podemos analisar a propriedade ParameterList nas propriedadeos do plano. Para isso, clique com o botão do lado direito do mouse no operador de select no plano de execução, e escolha a opção “Properties”, depois veja a propriedade “Parameter List“.

Propriedades - 1º Consulta

O valor utilizado no momento de compilação foi o mesmo utilizado no momento de RunTime.

Propriedades - 2º Consulta

O QO não conseguiu utilizar nenhum valor, portanto ele não aparece. Neste caso ele utilizou os 30%.

Propriedades - 3º Consulta

O valor utilizado no momento de compilação foi “0” porem no mento de RunTime o valor mudou para “10”.

Conclusão

Bom galera, fica a dica de quando, como e porque estes problemas são causados. Depois de entendido o problema resolve-los fica bem mais facil.

Abraço.


February 19

Profissional 5 estrelas, minhas considerações

Galera, fiz as provas do programa de profissional 5 estrelas de SQL Server no TechNet. Fiz o update do meu transcript para conseguir a 5º estrela, já que é necessário provar que você fez o exame 70-431 para obter a 5º estrela. Daqui a 72 horas úteis(nem sei quanto da isso em dias...) a 5º estrela deve aparecer no meu nome.

 

Segue minhas considerações em relação ao programa.

 

Bom, a uns 9 anos atrás quando eu ainda estava na fase pesada de estudos de informática, pra mim o programa foi bem interessante, cheguei a fazer várias provas de Segurança, ASP, C#, VB, .NET e etc... Na época isso foi legal e tals, e até que serviu bastante pra me ajudar a estudar sobre as tecnologias MS.

 

Mas hoje, penso que o programa deveria ser diferente. Se eu parar pra pensar, pra mim, para o que servem estas estrelas?

 

Acho que pra nada, na melhor das hipóteses para mim serviu como passatempo. Creio que a MS deveria ter um programa de incentivo para profissionais qualificados com 5 estrelas. Existem várias formas de fazer isso, seja divulgando melhor o nome deles, dar prêmios, descontos de softwares, voucher para certificação, convites para eventos, e por ai vai.. pensar em como fazer isso não problema meu é problema deles.. e eles tem pessoal de Marketing muito melhores do que eu para pensar nisso...

 

Considerações em ao material de estudo.

 

Os materiais são bem interessantes, mas é pouca coisa. O MSDN e TechNet tem MUITA coisa sobre SQL Server, portanto seria mais um “juntar” tudo e disponibilizar como material. Não precisa criar muita coisa nova, quase tudo já existe.

 

Por falar em juntar, na minha opinião ter tanta coisa em lugar separados é um grande problema, se é que podemos chamar isso de problema. Não tenho palavras para agradecer, todo o conteúdo que a MS disponibiliza para os profissionais que trabalham com seus softwares mas, isso não esta organizado. Nem um pouco organizado, tem coisa pra todo lado: MSDN, Technet, Support, Blogs, WebCasts, ScreenCasts, PodCasts, RadioCasts, Chats ... se eu fosse listar todos os sites que tenho em favoritos relacionados a estudos daria mais de 200... Ei estou falando só sobre SQL Server, imagina se pegarmos os conteúdos de Win... o dia em que eu tiver tempo vou atualizar minha lista de Blogs e vocês vão entender melhor o que eu estou dizendo.

 

Considerações em relação as provas.

 

Para quem fez o exame 70-431 e tem o livro de treinamento, as perguntas chegam a dar vergonha. Simplesmente 80 % das perguntas são exatamente as mesmas feitas no livro. Na minha opinião o famoso ctrl-c ctrl-v entrou em ação. O que é uma pena de ser ver. Aproveitando o pena, outra coisa chata é o título da página de ranking completo, “Untitled Page” sensacional.

 

Algumas perguntas estão escritas parte em inglês parte em português, por exemplo, pergunta em português e resposta em inglês. Como as perguntas foram traduzidas do livro, algumas foram até traduzidas incorretamente.

 

Eu não gosto disso. Na minha opinião ou é tudo em inglês ou tudo em português, ok, eu sei que tem algumas palavras ou mesmo expressões que é melhor deixar em inglês, mas como eu disse, isso são “algumas”.

Isso me lembra alguns projetos que trabalhei que envolviam empresas multinacionais. Comumente recebo documentos escritos metade em inglês e a outra metade em espanhol, e as vezes os dois misturados, isso sem contar com os comentários em português.

A sim é uma multinacional, então tudo bem, tudo bem nada. Pra mim é falta de organização, escolhe um idioma e todos tem que usar o mesmo e ponto.

 

Conteúdo para profissionais que finalizaram as 5º estrelas.

 

Ok, ganhei a 5º estrela, e agora?

 

O MSDN e TechNet dão muito valor aos profissionais que estão iniciando, não estou dizendo que isso é ruim, eu me lembro muito bem que um dia eu precisei desse valor. Mas para quem já tem um pouco de experiência com SQL Server, não temos muita coisa avançada. Quantas WebCasts nível 300,400 você já assistiu? Ok talvez algumas, mas com certeza nenhuma em português. Quantos artigos, ou programas são disponibilizados com um conteúdo mais focado para profissionais já certificados, pouquíssimos(no momento não me lembro de nenhum).

 

Ok, eu sei que alguns profissionais MS estão empenhados em ajudar o conteúdo disponibilizado para a comunidade, eu realmente admiro essa ação, mas sei que sozinhos, conseguem muito pouco.

 

Sinceramente, eu ADORO quando leio um texto e ao terminar de ler não tenho a menor idéia do que li J. Assim eu leio denovo, e denovo... até entender. Esses tipo de conteúdo que eu quero ver. Quer alguns exemplos?

 

A look at Virtual Address Space - VAS

How It Works: SQL Server Page Allocations

How It Works: SQLIOSim – Checksums

Analisando o trace flag 1118

 

Conclusão

 

Bom galera, a pergunta que fica é: Vale a pena obter as 5 estrelas?

 

Na minha opinião a resposta é sim. Mas eu realmente gostaria que um dia este meu “sim” soasse como “Cara essa você não pode perder”.

Abraço.

February 16

Fabiano VS dbo.fnTempoParaUmPost()

Saldo final do dia 16/02/2009:

 

Caixa de Entrada            =  0 itens

Itens Enviados no dia   =  128

Itens lidos e Excluídos =  185

 

Conclusão;

 

Caraca hoje foi um dia daqueles, já percebi que ia ser assim pois logo quando cheguei e abri o Outlook, vi que no sábado e domingo eu havia recebido 53 e-mails L.

 

Graças a Deus que no final tudo acabou bem J! Pronto para amanhã voltar a batalha.

February 12

Bad Sniff

Galera este será um post rápido,

Se alguem usa SQL Server 2000( ok quase todo mundo), e tem a seguinte situação….

Create proc st_test @i int, @x int
As
If @i = 10
  Set @i = 15
Select * from tab where id = @i and col_x = @x

Ou seja, voce altera o valor do parâmetro de entrada (variável @i), eu recomendo não fazer isso. Porque?

Porque SQL Server 2000 e Sniif simplismente não combinam… A cardinalidade vai pro saco, e o SQL pode( e vai ) gerar péssimos planos de execução.

Essa semana trabalhei em um desses casos, e quando eu tiver um tempinho vou preparar melhor uma base com exemplos para explicar melhor…

Fica a dica, não mude o valor de suas variáveis de entrada, o máximo que você pode fazer seria criar uma outra variável e usar ela. Mas isso tbm não é bom, e irá fazer com que o SQL utilize o lindo “magic density” que comentei neste post. O que pode ser bom, ou não, e na dúvida, prefiro ter certeza do que está acontecendo.

February 03

SQL Server 2008 Books Online (23 January 2009)

Saiu uma atualização do Books Online SQL 2008. Eu já estou baixando e você?

------------------------------

SQL Server 2008 Books Online (January 2009)

New and Updated Topics in SQL Server 2008 Books Online (23 January 2009)

The following technologies and categories have had new topics added or existing topics updated with significant changes in the 23 January 2009 release of SQL Server 2008 Books Online.

Getting Started: New and Updated Topics (23 January 2009)

Integration Services: New and Updated Topics (23 January 2009)

Database Engine: New and Updated Topics (23 January 2009)

Reporting Services: New and Updated Topics (23 January 2009)

January 30

07 Coisas que você precisa saber em relação "Statistics e Optimizer"

1.       Selectivity:

a.       Podemos definir seletividade como: O grau de um valor dentro de um determinado grupo, por exemplo, os jogadores da seleção de futebol são selecionados dentre milhares de opções que um técnico tem.

b.      Aplicando este conceito a banco de dados teríamos, em uma tabela de Clientes a coluna Tipo de Pessoa, pode ser J(Jurídica) ou F(Física), podemos dizer que o grau de seletividade é de baixo, pois só há duas variantes do valor dentre um todo. Por outro lado, uma coluna CPJ ou CNPJ será altamente seletiva, pois irá retornar apenas um registro dentre toda a tabela. 

2.       Density:

a.       O termo densidade vem da física, e é calculado por pela massa dividia por volume, uma representação matemática seria como na figura abaixo. Por exemplo, estamos um pouco mais acostumados a ouvir o termo densidade geográfica. A densidade geográfica do Brasil é calculada pela quantidade de habitantes dividida pelo tamanho da área geográfica, o que seria 187.000.000 dividido por 8.514.215,3 km2 que é igual a 21,96 habitantes por km2.

b.      No SQL Server podemos traduzir isso para: Quanto mais densa for uma coluna, mais registros ela retorna. Repare que é exatamente o contrário de seletividade, que quando mais seletiva for uma coluna menos registros ela retorna.

c.     Calculo matemático de densidade:

     

 

Onde D = Densidade, M = Massa e V é igual ao Volume.

d.      Para calcular a densidade de uma coluna você pode executar a consulta abaixo.

SELECT (1.0 / Count(Distinct <Column>))

 

3.       Cardinality:

a.       É utilizada para medir o número de linhas que satisfaçam uma condição. Por exemplo, imagine uma tabela com 500 linhas e uma consulta com where Nome = ‘Joao’, o SQL vai na estatística e lê no  histograma que o valor ‘Joao’ representa 5% da tabela, portanto a cardinalidade é de (5% * 500) = 25.

b.      Nos planos de execução podemos considerar a cardinality como a “estimated number of rows” apresentado nos operadores. Não preciso dizer que uma má interpretação na cardinality pode gerar um plano ineficiente, certo?

 

4.       SARG:

a.       SARG(Search Arguments) são condições de sua consulta. O valor que aparece no WHERE = “...” esse 3 pontinhos é o valor de pesquisa. Com base nesta informação o otimizador vai estimar quantas linhas serão retornadas e qual plano deverá utilizar para acessar esses dados. Ou seja, com base no argumento de consulta(SARG) informado o SQL analisa a selectivity, density e cardinality para gerar o plano.

5.       O que acontece quando o SQL não consegue estimar a cardinalidade de um valor(SARG) ?

a.       A cardinalidade e seletividade de um valor são informações essenciais para otimizador decidir qual plano usar. Sempre que possível durante a fase de criação do plano de execução(otimização), o SQL tenta executar transformar seus argumentos de consulta em constantes. Por exemplo, durante a fase de otimização, ele troca um “WHERE Valor = 1 + 1” por “WHERE Valor = 2“, e com base no “2” ele tenta ler nas estatísticas da tabela os dados necessários para ele tomar a decisão de qual plano gerar.

b.      O otimizador não consegue identificar(leia-se sniff) o valor de um argumento de consulta por vários motivos, vou destacar alguns:

                                                               i.      Quando na constante é utilizado uma função que seja diferente das listadas abaixo:

1.       Lower, Upper, RTrim, Datediff, Dateadd, Datepart, Substring, Charindex, Len, SUser_SName, IsNull, GetDate, GetUTCDate;

2.       Exemplos:

1.       “WHERE <coluna> = ABS(-1000)”, para que o SQL consiga utilizar o argumento de consulta, você poderia trocar o comando por “WHERE <coluna> = -1000 * -1”

2.       “WHERE <coluna> = REPLACE('xx8888888', 'xx', '88')”: Não consegue gerar a cardinalidade.

3.       “WHERE <coluna> = LEN(88888888)”: Consegue gerar cardinalidade normalmente.

                                                             ii.      Quando utilizado variáveis locais. Por exemplo:

DECLARE @I Int

SELECT * FROM <tabela>

 WHERE <Coluna> = @I

                                                            iii.      Quando utilizado scalar-valued user-defined functions.

 SELECT * FROM <tabela>

  WHERE <coluna> = dbo.fn_FormataTexto('Texto')

                                                           iv.      Quando é utilizado um operador de diferença, por exemplo o <>, o argumento de consulta não é valido.

                                                             v.      Consultas do tipo “WHERE <coluna> = (select <coluna> from <tabela>)”, não permitem que o argumento seja utilizado, pois o resultado da subquery não é conhecido no momento da geração do plano.

 

c.       Quando o otimizador não consegue identificar qual é a cardinalidade de um valor, ele usa o que chamamos de Magic Density(haha eu adoro esse nome), também conhecido por “Guess”, resumindo, ele tenta “adivinhar” quantas linhas serão retornadas. Para isso ele usa a densidade da coluna ou então ele usa um percentual fixo. Vejamos alguns exemplos de como ele faz esta “mágica”.

d.      A partir do SQL Server 2000 funciona assim:

1.  -- Para =, Usa COUNT(*) * Density da coluna ou seja, COUNT(*) * (1.0 / (COUNT (DISTINCT <coluna>)))

2.  SELECT *

3.    FROM <tabela>

4.   WHERE <coluna> = @I

 

5.  -- Para BETWEEN, Usa 9% ou seja, (COUNT(*) * 9.0) / 100

6.  SELECT *

7.    FROM <tabela>

8.   WHERE <coluna> BETWEEN @I AND @X

 

9.  -- Para >, >=, < e <=, Usa 30% ou seja, (COUNT(*) * 30.0) / 100

10.SELECT *

11.  FROM <tabela>

12.    WHERE <coluna> “>, >=, < e <=” @I

e.      Importante: No SQL Server 2000 tem um detalhe que é um pouco diferente, os percentuais utilizados(9% e 30%) não mudam, porem ao utilizar o between o otimizador consegue identificar um comportamento bem interessante, coisa que a partir do SQL2005 foi alterado e ao meu ver está errado, deveria voltar como era no 2000. No SQL 2000, se eu escrever uma consulta assim:

1.        SELECT *

2.          FROM <tabela>

3.         WHERE <coluna> BETWEEN @I AND @I

 

Repare que a consulta utiliza a variável @I duas vezes, ou seja este between é a mesma coisa que um WHERE <coluna> = @I. Neste caso o SQL 2000 gera a seguinte instrução de argumento:

 

OBJECT:([dbo].[<tabela>].[PK_...]), WHERE:([ <tabela>].[<coluna>]=[@I])

 

Já o nosso querido SQL 2005 e 2008 geram o seguinte;

 

OBJECT:([dbo].[<tabela>].[PK_...]), WHERE:( [dbo].[ <tabela>].[<coluna>]>=[@I] AND [dbo].[ <tabela>].[<coluna>]<=[@I])

 

Pois é, ele não é esperto o suficiente para identificar que “BETWEEN @I AND @I” é igual a “= @I”. Outra coisa interessante é que se você rodar a consulta no SQL 2005\2008 utilizando o hint OPTION(RECOMPILE) ele gera o plano corretamente, igual ao SQL 2000.

 

6.       RowModCtr:

a.       Existe uma coluna na tabela sysindexes do SQL 2005 ou sys.sysindexes para posteriores, onde podemos observar quantas alterações ocorreram em uma determinada coluna deste a última atualização das estatísticas.

b.      Sempre que acontece um INSERT, DELETE ou UPDATE envolvendo a coluna da estatística, o SQL Server atualiza este valor.

c.       Quando as estatísticas são atualizadas, esta coluna é zerada.

d.      Caso você queira ter mais controle sobre quando disparar um UPDATE STATISTICS, você pode utilizar esta coluna para ver quantas alterações ocorreram na tabela, e decidir se deve disparar uma atualização ou não.

7.       Quando um auto update statistics é disparado?

a.       Sempre que uma coluna que pertence a uma estatística alcança um número suficiente de modificações, o SQL Server dispara o auto update statistics para manter os dados atualizados. Este controle funciona assim:

                                                               i.      Se a quantidade de linhas da tabela for menor que 6 e for uma tabela temporária(#), atualiza as estatísticas a cada 6 modificações na tabela.

                                                             ii.      Se a quantidade de linhas da tabela for maior que 6, porem menor ou igual a 500, atualiza as estatísticas a cada 500 modificações na tabela.

                                                            iii.      Se a quantidade de linhas da tabela for maior que 500, atualiza as estatísticas a cada (500 + 20% da tabela) modificações na tabela. Portanto, uma tabela com 1000 linhas, só sofreria uma atualização automática quando a rowmodctr atingisse 700 modificações.

                                                          iv.      Só lembrando que variáveis do tipo table, não tem estatisticas portanto elas não geram um auto update.

b.      Pergunta, tem como visualizar quando o auto update é disparado?

                                                               i.      Tem várias formas, segue algumas:

1.       Se a coluna rowmodctr estiver zerada isso significa que o auto update acabou de ser executado.

2.       No profiler selecione as colunas SP:StmtCompleted e SP:StmtStarting que quando o UPDATE for disparado você verá o código utilizado pelo SQL para pegar as informações da coluna. Verá algo mais ou menos parecido com o código abaixo:

SELECT StatMan([SC0])

  FROM (SELECT TOP 100 PERCENT <coluna> AS [SC0]

          FROM [dbo].<tabela> WITH (READUNCOMMITTED)

                                 ORDER BY [SC0] ) AS _MS_UPDSTATS_TBL

3.       Você pode habilitar o traceflag 205 para fazer com que o SQL grave uma informação no arquivo de error log.

4.       O traceflag 8721 também grava uma informação no error log.

 

Quer mais? Boa Leitura:  

Troubleshooting Poor Query Performance: Constant Folding and Expression Evaluation During Cardinality Estimation

Troubleshooting Poor Query Performance: Cardinality Estimation

Statistical maintenance functionality (autostats) in SQL Server

INF: Search Arguments That Determine Distribution Page Usage

Statistics Used by the Query Optimizer in Microsoft SQL Server 2000

Statistics Used by the Query Optimizer in Microsoft SQL Server 2005

Batch Compilation, Recompilation, and Plan Caching Issues in SQL Server 2005

Use Parameters or Literals for Query Inputs

I Smell a Parameter!

How to update statistics for large databases

How It Works: Statistics Sampling for BLOB data

Index Statistics

Support WebCast: Effective Indexing and Statistics with SQL 2000


January 29

Operador do dia - Nonclustered Index Spool

clip_image001[3] Nonclustered Index Spool

Continuando a falar sobre os operadores de Spool, o próximo da lista é o Nonclustered Index Spool.

Para melhor entendimento do assunto, caso não tenha lido os outros posts onde falei sobre Spool, recomendo que leia.

Operador do dia - Spool

Operador do dia - Eager Spool e “Halloween Problem”

Operador do Dia - Lazy Spool

Assim como os outros tipos de Spool, o Index Spool pode ser utilizado como Lazy e Eager. Ele é utilizado para agilizar na leitura de uma tabela que não está indexada. Quando o SQL precisa ler um valor que não esta indexado ele pode optar por criar um “índice temporário” utilizando o Spool.

Isso pode agilizar e muito as suas consultas, vamos ver um exemplo prático deste uso.

Para ilustrar o uso do Index Spool criei uma tabela chamada Pedidos. Segue o script para criação e carga dos dados:

IF OBJECT_ID('Pedido') IS NOT NULL

  DROP TABLE Pedido

GO

CREATE TABLE Pedido (ID         Int IDENTITY(1,1) PRIMARY KEY,

                     Cliente    Int NOT NULL,

                     Vendedor   VarChar(30) NOT NULL,

                     Quantidade SmallInt NOT NULL,

                     Valor      Numeric(18,2) NOT NULL,

                     Data       DateTime NOT NULL)

 

DECLARE @I SmallInt

SET @I = 0

 

WHILE @I < 50

BEGIN

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT ABS(CheckSUM(NEWID()) / 100000000),

         'Fabiano',

         ABS(CheckSUM(NEWID()) / 10000000),

         ABS(CONVERT(Numeric(18,2), (CheckSUM(NEWID()) / 1000000.5))),

         GetDate() - (CheckSUM(NEWID()) / 1000000)

 

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT ABS(CheckSUM(NEWID()) / 100000000),

         'Amorim',

         ABS(CheckSUM(NEWID()) / 10000000),

         ABS(CONVERT(Numeric(18,2), (CheckSUM(NEWID()) / 1000000.5))),

         GetDate() - (CheckSUM(NEWID()) / 1000000)

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT ABS(CheckSUM(NEWID()) / 100000000),

         'Coragem',

         ABS(CheckSUM(NEWID()) / 10000000),

         ABS(CONVERT(Numeric(18,2), (CheckSUM(NEWID()) / 1000000.5))),

         GetDate() - (CheckSUM(NEWID()) / 1000000)

  SET @I = @I + 1 

END

SET @I = 0

WHILE @I < 2

BEGIN

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT Cliente, Vendedor, Quantidade, Valor, Data

    FROM Pedido

  SET @I = @I + 1 

END

GO

Exemplo dos dados da tabela:

clip_image002[3]

Para simular o uso do Index Spool, criei uma consulta que retorna todos os pedidos que tiveram venda maior que a média de venda,

comparado a todas as vendas anteriores a data de venda atual.

SELECT *

  FROM Pedido Ped1

 WHERE Ped1.Valor > (SELECT AVG(Ped2.Valor)

                       FROM Pedido AS Ped2

                      WHERE Ped2.Data < Ped1.Data)

Antes de ver o plano vamos entender melhor a consulta.

A SubConsulta retorna a média de venda (AVG(Ped2.Valor)) em uma determinada data da tabela do from(Ped1.Cliente), depois a consulta principal, pega esta média, e retorna as vendas que tiveram o valor maior que ela.

O plano de execução é o seguinte:

clip_image003[3]

 

SELECT *    FROM Pedido Ped1   WHERE Ped1.Valor > (SELECT AVG(Ped2.Valor)                         FROM Pedido AS Ped2                        WHERE Ped2.Data < Ped1.Data)

  |--Filter(WHERE:([tempdb].[dbo].[Pedido].[Valor] as [Ped1].[Valor]>[Expr1004]))

       |--Nested Loops(Inner Join, OUTER REFERENCES:([Ped1].[Data]))

            |--Clustered Index Scan(OBJECT:([tempdb].[dbo].[Pedido].[PK__Pedido__3214EC2753C82368] AS [Ped1]))

            |--Index Spool(SEEK:([Ped1].[Data]=[tempdb].[dbo].[Pedido].[Data] as [Ped1].[Data]))

                 |--Compute Scalar(DEFINE:([Expr1004]=CASE WHEN [Expr1011]=(0) THEN NULL ELSE [Expr1012]/CONVERT_IMPLICIT(numeric(19,0),[Expr1011],0) END))

                      |--Stream Aggregate(DEFINE:([Expr1011]=Count(*), [Expr1012]=SUM([tempdb].[dbo].[Pedido].[Valor] as [Ped2].[Valor])))

                           |--Index Spool(SEEK:([Ped2].[Data] < [tempdb].[dbo].[Pedido].[Data] as [Ped1].[Data]))

                                |--Clustered Index Scan(OBJECT:([tempdb].[dbo].[Pedido].[PK__Pedido__3214EC2753C82368] AS [Ped2]))

Este plano é bem interessante, e podemos observar que o SQL optou por usar 2 Index Spool, um como Eager e outro como Lazy. Vemos também que depois do Nested Loops, o SQL utiliza o operador de Filter para selecionar apenas as linhas que satisfaçam a condição no where(WHERE Ped1.Valor > ...).

Vamos iniciar a analise mais profunda do plano e, entender alguns conceitos em relação a leitura e calculo dos dados pelos operadores.

O operador de Clustered index Scan, lê os dados da tabela Pedidos e retorna as colunas Valor e Data para o Operador de Eager Index Spool. Com as colunas Data e Valor ordenadas no índice, o SQL utiliza o Index Spool para selecionar todas as linhas onde a Data seja menor que a data da tabela Ped1. Durante a primeira leitura dos dados o Eager Index lê todas as linhas da tabela e grava no índice.

Vemos também que o SQL optou por utilizar o operador de Nested Loops, esta operação faz uma leitura completa da tabela do from, e para cada linha lida ele vai na tabela do join procurar pelo seu valor correspondente. Após a conclusão do Nested Loops, o SQL retorna todas as colunas da tabela Pedidos, mais o valor da média, que é representado pelo valor “Expr1004”. Este valor é o resultado do calculo efetuado pelo Compute Scalar. Isso pode ser confirmado analisando o hint output dos operadores de Nested Loops e Compute Scalar.

clip_image004[3]clip_image005[3]

Temos então a seguinte regra: Para cada linha do from(Ped1) calcula a média sendo que Ped2.Data. tem que ser menor que Ped1.Data.

Para calcular esta média, o SQL utilizou o Stream Aggregate mais o Compute Scalar.

Dada esta introdução, chegamos onde eu queria.

Quando o SQL Server precisa ler um valor que ele sabe que repete várias vezes, ele pode utilizar o Spool para não precisar calcular um valor que já foi calculado. Por exemplo, digamos que a coluna data tenha um grau de densidade alto, ou seja, os valores duplicam bastante dentro da massa da tabela. Isso irá acarretar em um mesmo calculo mais de uma vez, já que o Nested Loops vai chamar os passos do join para cada linha lida no from. Se o valor passado como condição para o join é igual ao valor que já foi calculado, então não precisa calcular os dados novamente. O ideal neste caso é que o calculo que já foi feito seja reaproveitado.

O operador de Index Spool trabalhando como Lazy é desenhado para otimizar o processo do Join, isso significa que ele é otimizado para prever justamente este caso que citei, um valor que já foi calculado não será calculado novamente, mas ele lê este valor na tabela que esta em cache (tempdb). Portanto para o Spool é importante distinguir entre a execução do join com um novo parâmetro ou um parâmetro que já foi utilizado.

É possível identificar pelo plano de execução, quando o Spool teve que recalcular um valor e quando ele reutilizou um valor já calculado, basta analisar os valores de Rewind e Rebind. Onde:

· Rewind: Definido pela execução do mesmo parâmetro. Um rewind faz com que o Spool leia os dados que estão em cache.

· Rebind: Acontece quando um novo parâmetro é enviado para execução. O rebind faz com que o Spool calcule um novo valor e carregue o resultado para o cache.

Aproveitando que estamos falando sobre os operadores, o rewind e rebind ocorrem no método Init() do operador. Só para deixar mais claro, sempre que um operador é executado ele executa 3 métodos, são eles:

· Init() – Neste método o operador é inicializado e carrega as informações que são necessárias para sua execução. Este método é chamado pelo menos 1 vez, porem dependendo do operador ele pode ser chamado mais de uma vez. No caso dos operadores de spool, sempre que este método é chamado ocorre um rebind ou rewind.

· GetNext() – Lê a primeira ou subsequente linha dos dados. Cada vez que o GetNext() é chamado o SQL lê a linha necessária para executar sua operação.

· Close() – Finaliza o operador e libera os dados utilizados por ele.

Vamos supor uma tabela simples, com alguns registros na seguinte ordem, 1,1,2 e 1. Uma representação do Rewind e Rebind na prática seria algo mais ou menos assim:

  1. Valor = 1, rebind ocorre já que é a primeira vez que o operador é chamado. Calcula o valor e joga no cache do Spool.
  2. Valor = 1, rewind ocorre já que o valor para 1 já foi calculado e está em cache.
  3. Valor = 2, rebind ocorre pois o valor 2 ainda não foi calculado. Calcula o valor e joga no cache do Spool. O spool só consegue gravar um valor por vez, portanto neste caso calculo para o valor 1 é truncado, para dar lugar ao valor do calculo 2.
  4. Valor = 1, rebind ocorre já que o valor para 1 não está mais em cache, pois ele foi truncado quando o rebind para o passo 3 ocorreu.

Normalmente os operadores de Spool apagam os dados de sua tabela temporária a cada Rebind, ou seja, sempre que ele precisar calcular um novo valor, antes de iniciar o calculo ele apaga os dados atuais. Quando o valor subseqüente é igual, o Lazy Index Spool consegue identificar que não é necessário fazer um rebind e reutiliza o valor gravado no cache.

Na minha opinião, o Lazy Spool seria mais eficiente se ele não truncasse os dados, sempre que ele precisar fazer um Rebind. Ao manter os dados em cache, ele conseguiria fazer um novo rewind no nosso exemplo(ponto 4), e assim evitaria ter que calcular um valor que ele já calculou.

Eu entrei em contato com o Craig Freedman para dar esta sugestão e confirmar se o SQL realmente truncava o valor a cada rebind, ele confirmou que é isso mesmo, pois o spool só consegue trabalhar com um valor por vez. Portanto, é uma pena.

Lembrando que o Otimizador verifica se é necessário utilizar o Lazy Index baseado no custo da operação, quando a densidade da coluna for muito alta e o custo for spool for menor que refazer o calculo(reler o valor na origem e não na tabela temporária do spool). Por enquanto segue o link para a explicação do Gustavo Maia, estou escrevendo um novo post onde vou falar um pouco mais sobre, como a densidade de uma coluna pode ser visualizada, calcula e quando ela é utilizada.

Fica a seguinte dica, normalmente quando vemos um Index Spool, isso significa que se criarmos um índice pelas colunas que ele utilizou, é bem provável que o Spool suma, e o SQL passe a utilizar o novo índice.

É isso ai galera, falta apenas falar sobre o RowCount Spool e podemos passar para outro operador. Fique de olho, e se tiver sugestão de algum operador, é só postar um comentário.

Abraço.

Recovery Model Bulk-logged

Pessoal vamos deixar uma coisa bem clara.

O Recovery Model Bulk-Logged NÃO é o recovery que grava menos LOG.

Por se chamar Bulk-Loogger isso não significa que ele só grava operações de bulk. Pelo contrário na verdade isso significa que ele não grava operações de bulk.

Portanto para ambientes de desenvolvimento, testes ou mesmo bases OLAP, onde não é necessário fica fazendo backup para voltar a um determinado tempo. O Ideal será utilizar o recovery Simple.

Eu já ouvi várias vezes, dizerem que o Bulk é melhor que o Simple.

Veja bem, o Bulk-Logged é semelhante ao Full, a diferença entre eles é que o Bulk não grava operações de Bulk como, SELECT INTO, BCP, BULK INSERT,CREATE INDEX e operações com os tipos de dados texto e ntext.

Segue alguns links que comprovam o que eu escrevi:

http://msdn.microsoft.com/pt-br/library/ms186229.aspx

“Geralmente, o modelo de recuperação bulk-logged é semelhante ao modelo de recuperação completa e as informações descritas para o modelo de recuperação completa também se aplicam a ambos.”

http://www.devmedia.com.br/articles/viewcomp.asp?comp=6458&hl=

“Este modelo registra muito mais informação no log de transações do que o modelo SIMPLE. A única informação não registrada são operações de volume como: SELECT INTO, BCP, BULK INSERT,CREATE INDEX e operações com os tipos de dados texto e ntext.”

http://blogs.msdn.com/luti/archive/2007/03/29/log-sequence-number-lsn-e-a-tabela-backupset-backup-restore-parte-1-de.aspx

“Quando o banco de dados está com o recovery model full ou Bulk-logged, todas as transações processadas pelo SQL Server são registradas no log de transação (arquivos .ldf), e cada instrução executada recebe um número de seqüência (LSN).”

January 26

Operador do dia - Lazy Spool

clip_image001 Lazy Spool

Continuando a falar sobre os operadores de Spool, o próximo da lista é o Lazy Spool.

Para melhor entendimento do assunto, caso não tenha lido os outros posts onde falei sobre Spool, recomendo que leia.

Operador do dia - Spool

Operador do dia - Eager Spool e “Halloween Problem”

O Lazy Spool é bem parecido com o Eager Spool, porém a grande diferença entre eles é que o Lazy lê os dados conforme as linhas são requisitadas, a cada acesso ao operador, ele lê apenas uma linha, diferentemente do Eager que logo no primeiro acesso lê todos os dados.

Para ilustrar o uso do Lazy Spool criei uma tabela chamada Pedidos. Segue o script para criação e carga dos dados:

IF OBJECT_ID('Pedido') IS NOT NULL

  DROP TABLE Pedido

GO

 

CREATE TABLE Pedido (ID         Int IDENTITY(1,1) PRIMARY KEY,

                     Cliente    Int NOT NULL,

                     Vendedor   VarChar(30) NOT NULL,

                     Quantidade SmallInt NOT NULL,

                     Valor      Numeric(18,2) NOT NULL,

                     Data       DateTime NOT NULL)

 

DECLARE @I SmallInt

SET @I = 0

 

WHILE @I < 50

BEGIN

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT ABS(CheckSUM(NEWID()) / 100000000),

         'Fabiano',

         ABS(CheckSUM(NEWID()) / 10000000),

         ABS(CONVERT(Numeric(18,2), (CheckSUM(NEWID()) / 1000000.5))),

         GetDate() - (CheckSUM(NEWID()) / 1000000)

 

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT ABS(CheckSUM(NEWID()) / 100000000),

         'Amorim',

         ABS(CheckSUM(NEWID()) / 10000000),

         ABS(CONVERT(Numeric(18,2), (CheckSUM(NEWID()) / 1000000.5))),

         GetDate() - (CheckSUM(NEWID()) / 1000000)

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT ABS(CheckSUM(NEWID()) / 100000000),

         'Coragem',

         ABS(CheckSUM(NEWID()) / 10000000),

         ABS(CONVERT(Numeric(18,2), (CheckSUM(NEWID()) / 1000000.5))),

         GetDate() - (CheckSUM(NEWID()) / 1000000)

  SET @I = @I + 1 

END

SET @I = 1

WHILE @I < 3

BEGIN

  INSERT INTO Pedido(Cliente, Vendedor, Quantidade, Valor, Data)

  SELECT Cliente, Vendedor, Quantidade, Valor, Data

    FROM Pedido

  SET @I = @I + 1 

END

GO

 

Exemplo dos dados da tabela:

clip_image003

Para simular o uso do Lazy Spool, criei uma consulta que retorna todos os pedidos que tiveram venda maior que a média de venda,

comparado a todas as vendas para o mesmo cliente.

SELECT Ped1.Cliente, Ped1.Valor

  FROM Pedido Ped1

 WHERE Ped1.Valor < (SELECT AVG(Ped2.Valor)

                       FROM Pedido Ped2

                      WHERE Ped2.Cliente = Ped1.Cliente)

 

Antes de ver o plano vamos entender melhor a consulta.

A SubConsulta retorna a média de venda (AVG(Ped2.Valor)) de um determinado cliente da tabela do from(Ped1.Cliente), depois a consulta principal, pega esta média, e retorna as vendas que tiveram o valor maior que ela.

O plano de execução é o seguinte:

clip_image005 

  |--Nested Loops(Inner Join)

       |--Table Spool

       |    |--Segment

       |         |--Sort(ORDER BY:([Ped1].[Cliente] ASC))

       |              |--Clustered Index Scan(OBJECT:([tempdb].[dbo].[Pedido].[PK__Pedido__6E01572D] AS [Ped1]))

       |--Nested Loops(Inner Join, WHERE:([tempdb].[dbo].[Pedido].[Valor] as [Ped1].[Valor]<[Expr1004]))

            |--Compute Scalar(DEFINE:([Expr1004]=CASE WHEN [Expr1012]=(0) THEN NULL ELSE [Expr1013]/CONVERT_IMPLICIT(numeric(19,0),[Expr1012],0) END))

            |    |--Stream Aggregate(DEFINE:([Expr1012]=Count(*), [Expr1013]=SUM([tempdb].[dbo].[Pedido].[Valor] as [Ped1].[Valor])))

            |         |--Table Spool

            |--Table Spool

 

Podemos observar que o operador de Spool aparece 3 vezes no plano de execução, isso não significa que existem 3 tabelas temporárias, na verdade os 3 compartilham a mesma tabela temporária, isso pode ser observado analisando os hints exibidos pelos operadores.

clip_image007

Repare que o primeiro Spool tem o Node ID 2, e os outros operadores fazem referencia ao Primary Node 2.

Vou tentar detalhar este plano de execução o máximo possível, para que fique um pouco mais fácil de entender o que está acontecendo.

O primeiro passo do plano é ler os dados envolvidos na consulta e agrupá-los por cliente.

clip_image009 Primeiro o operador de clustered index scan está lendo os dados das colunas clientes e valor.

Input() do operador é:

clip_image011

Output() = Colunas Cliente e Valor.

clip_image013

clip_image015 Ao receber o Output() do clustered index scan, o operador de Sort ordena o resultado pela coluna cliente.

Input() = Output() anterior a ele(clustered index scan)

Output() = Dados ordenados por Cliente

clip_image017

clip_image019 O operador Segment quebra os dados em vários grupos, neste caso, ele recebe os dados ordenados por cliente, e quebra os dados em grupos que compartilham o mesmo cliente. O primeiro grupo serão os dados que compartilham o Cliente “0”. Como os dados estão ordenados por cliente, ele só precisa ir lendo as linhas até encontrar um valor diferente do atual(“0”). Quando isso acontece ele passa seu output() para o próximo operador, e espera o processo voltar até ele para que ele calcule o próximo grupo de dados até terminar sua leitura.

Input() = Output() anterior a ele(Sort)

Output() = Grupo de dados (primeiro grupo “Cliente = 0”)

clip_image017[1]

clip_image021 Aqui vemos o Table Spool trabalhando como Lazy, ou seja, lê os dados conforme requisição. Ele cria uma tabela temporária no tempdb armazenando os dados que contem o mesmo grupo de Cliente.

Input() = Resultado do Segment

Output() = Tabela com os dados armazenados no tempdb

clip_image023 Faz o join entre a tabela do from com a tabela do join. Neste caso, para cada linha do Table Spool faz um scan nas linhas do próximo join retornando as linhas que satisfaçam o join.

Vamos passar para o segundo passo do plano. Onde o SQL vai calcula a média de venda de um determinado cliente.

clip_image021[1] Lê os dados atuais do Spool, e passa o resultado para o aggregate calcular a média. Lembrando que os registros do Spool são exatamente o grupo de clientes “0”.

clip_image025 O Stream Aggregate lê os dados do Spool e calcula a média da coluna valor, retornando apenas 1 registro como parâmetro de saída.

clip_image027 Converte o resultado da aggregação no tipo Numeric para fazer o join com o valor do Spool.

clip_image023[1] Faz o join entre a tabela do from com a tabela do join. Neste caso, para cada valor computado, faz um scan no table spool retornando as linhas que satisfaçam o join, ou seja, onde o Valor do Table Spool for maior que o valor retornado pela agregação.

clip_image021[2] O ultimo table spool é utilizado pelo Nested Loops para fazer o join com o valor do stream aggregate.

Ao terminar este processo o operador de segment é executado novamente, desta vez repetindo todo o processo passando para o spool o próximo grupo de dados.

Ao utilizar o Spool o SQL Server só precisa ler a tabela Pedidos uma única vez, todos os acessos posteriores a primeira leitura são efetuados no spool, que por sua vez só guarda os valores de um segmento por vez.

Vou tentar ilustrar o que aconteceu aqui:

1 - O Nested Loop lê a primeira linha no Table Spool. Faz um scan com todos os clientes que resultaram do 2 Nested Loop, que irá retornar as linhas onde o valor é maior que a média.

clip_image029

2 - Executa o segundo join. Verifica quais as linhas que tem o valor maior que a média.

3 - Calcula a média para o cliente atual(0).

clip_image031

Para o resultado da média, verifica quais as linhas que satisfaçam o join. Por ex: 1275.91 é maior que 362.78? Caso seja verdadeiro então retorna o Cliente e o Valor, senão passa para o próximo registro do table spool. Repete este processo até terminar a leitura de todos os registros do spool.

4 - Faz um Join com o resultado do 2 Nested Loop.

5 - Chama o segment que limpa o Spool e passa para o próximo grupo de dados, iniciando novamente o processo 1.

Pessoal, vimos o uso do Lazy Spool para trabalhar com joins, evitando acessar uma tabela várias vezes, otimizando o processo de execução da consulta.

Ainda falta vermos os RowCount Spool e o Nonclustered Index Spool. Fique de olho.

Abraço.

January 23

Interview Question

Hi Folks

Recentemente li um post bem interessante onde o autor citava 10 perguntas que ele faz em uma entrevista para contratação de um DBA Senior, seja ele desenvolvedor ou administrador.

A primeira pergunta era mais focada a desenvolvimento e, como é minha praia, achei bem interessante e vou compartilhar minha opinião com vocês.

É mais ou menos assim:

Escreva um código onde você irá printar números de 1 a 100, quando o número for múltiplo de 3 você irá escrever ”Fizz”, quando o número for múltiplo de 5 você irá escrever “Buzz” e quando o número for múltiplo de 3 e 5 escreva “FizzBuzz”.

Existem várias maneiras de escrever este código, a intenção não é ver qual é o melhor código, mas sim apurar a lógica de programação e agilidade em lidar com problemas em tempo hábil.

Um desenvolvedor que se preze não deve levar mais de 10 minutos para escrever um código desses, e se for capaz tente escrever sem compilar o código, apenas escreva o comando e depois de terminar ai sim compile. Não tem problema se der algum erro na primeira compilação, mas se você conseguir fazer o código funcionar sem erro na primeira execução, isso mostra que sua lógica e prática de desenvolvimento realmente existem, e são dignas de serem reconhecidas como “Senior”. Mas lembre-se, o mais importante é fazer com que o código funcione.

Eu é claro, escrevi o código e, confesso que da primeira vez que compilei não deu erro, mas a lógica estava errada devido a uma falta de atenção minha, assim que compilei vi o erro corrigi e rodei de novo com sucesso. Fica a dica, não faça como eu, escreva o código e depois revise ele para ver se não ficou algum GAP pra traz.

Meu código está aqui, não baixe antes de tentar escrever o seu código, não minta para você mesmo.