Você está na página 1de 7

Entendendo Physical Joins

Qual a diferena entre os operadores de join fsicos? Como eles diferem entre si e em que cenrios um prefervel em relao ao outro?

Usamos os operadores lgicos quando escrevemos consultas em um nvel conceitual (o que precisa ser feito). O SQL implementa estes operadores lgicos com trs operadores fsicos para implementar as operaes. Apesar de existir dezenas de operadores fsicos, aqui vamos cobrir apenas os operadores de join. Apesar de termos tipos diferentes de operadores lgicos a nvel conceitual/consulta, o SQL Server as implementa com os trs operadores fsicos discutidos abaixo.

*Nested Loops Join*

Antes de entrar em detalhes, vamos ver o que um Nested Loops join no mundo das linguagens de programao. Um Nested Loops join uma estrutura em que uma iterao acontece dentro de outra, o que significa dizer que para cada iterao do loop externo todas a iteraes do loop interno so executadas/processadas.

Um Nested Loops join funciona da mesma maneira. Uma das tabelas participantes eleita como a tabela externa e outra como a tabela interna (inner table). Para cada registro da tabela externa, todos os registro da inner table so lidos um a um, se as linhas coincidem ento ela incluida no resultset caso contrrio ignorado. Ento o prximo registro da outer table obtida e o mesmo processo se repete at o fim.

O otimizador do SQL Server pode escolher um Nested Loops join quando uma das tabelas do join pequena (considerada como a outer table) e a outra grande (considerada como a inner table que indexada pelo campo que est no join) e assim requer o mnimo de I/O e o menor nmero de comparaes.

O otimizador avalia trs variaes para o Nested Loops join:

* Naive Nested Loops join no caso de pesquisar toda a tabela ou indice * Index Nested Loops join quando a pesquisa puder utilizar um ndice j existe para fazer os lookups * Temporary Index Nested Loops Join se o otimizador criar um ndice temporrio como parte do plano de execuo e destrui-lo quando a execuo da consulta terminar.

Um index nested loops join tem melhor desempenho do que um Merge Join ou o Hash Join se um pequeno nmero de linhas estiver envolvido. Porm, se um grande conjunto de registros estiver envolvido o Nested Loops join pode no ser uma escolha otimizada. Nested Loops suportam quase todos os tipos de join exceto o Right e Full Outer Joins, Right Semi-Join e Right Anti-Semi Join.

No Script #1, fazemos o join da tabela \SalesOrderHeader com a tabela \SalesOrderDetail e especificamos uma condio de filtro com \CustomerID = 670. Este critrio de filtro retorna 12 registro da tabela \SalesOrderHeader e assim por ser a menor, esta tabela foi escolhida como a outer table (no topo do plano de execuo grfico) pelo otimizador. Para cada registro destas 12 linhas da outer table, linhas da inner table so comparadas (ou a inner table pesquisada 12 vezes para cada registro usando um index seek ou parmetro correlacionado da outer table) e 312 registros iguais so retornados como podemos ver na segunda imagem. Na segunda query, estamos usando SET STATISTICS PROFILE ON para mostrar as informaes de profile da execuo da query junto com o resultado.

Script #1 - Nested Loops Join <<pre SELECT H.CustomerID, H.SalesOrderID, D.ProductID, D.LineTotal FROM Sales.SalesOrderHeader H INNER JOIN Sales.SalesOrderDetail D ON H.SalesOrderID = D.SalesOrderID WHERE H.CustomerID = 670 >> file:///C:/Util/WikidPad/MyWiki/NestedLoopsJoin.jpg <<pre SET STATISTICS PROFILE ON

SELECT H.CustomerID, H.SalesOrderID, D.ProductID, D.LineTotal FROM Sales.SalesOrderHeader H INNER JOIN Sales.SalesOrderDetail D ON H.SalesOrderID = D.SalesOrderID WHERE H.CustomerID = 670 SET STATISTICS PROFILE OFF >> file:///C:/Util/WikidPad/MyWiki/NestedLoopsJoin_grid.jpg

Se o nmero de registros for grande, o SQL Server pode escolher paralelizar o nested loop distribuindo os registros da outer table aleatoriamente entre vrias threads de Nested Loops. Porm o mesmo no se aplica aos registros da inner table. Para saber mais sobre scan em paralelo clique aqui: http://blogs.msdn.com/b/craigfr/archive/2006/11/01/parallel-scan.aspx.

*Merge Join*

A primeira coisa que devemos saber sobre o Merge join que ele requer que ambas as entradas estejam ordenadas (sorted) pelas colunas do join keys/merge (ou ambas as tabelas tenham os campos no ndice cluster) e tambm requer pelo menos uma expresso/predicado do tipo equijoin (igual a).

Como os registro esto pr ordenados, o Merge join comea a fazer o processo de comparaes imediatamente. Ele l um registro de uma entrada e compara com o registro da outra entrada. Se elas so iguais, ento o registro includo no result-set (entro ele l o prximo registro da tabela de entrada, faz a mesma comparao e assim por diante) ou ento o menor valor dos dois registros ignorado e o processo continua desta maneira at processar todos os registros...

O Merge join tem melhor desempenho quando comparamos grande tabelas de entrada (pr indexadas / ordenadas) com o custo sendo a soma das linhas de ambas as tabelas ao contrrio do Nested Loops onde ele o produto dos

registros de ambas as input tables. Algumas vezes o otimizador decide usar um Merge join quando a input table no est em ordem e assim ele executa um operador de sort fsico explicito, mas pode ser mais lento do que usar uma tabela de entrada pr ordenada.

No script #2, usamos uma query parecida com a anterior, mas desta vez adicionamento uma clusula WHERE para obter todos os cliente maiores que 100. Neste caso o otimizador decidiu usar um Merge join pois ambas as tabelas so grandes em termos de registros e tambm esto pr indexadas/ordenadas. Podemos ver que amabas as tabelas foram lidas uma vez ao contrrio das 12 vezes que vimos no Nested Loops join acima.

Script #2 - Merge Join <<pre SELECT H.CustomerID, H.SalesOrderID, D.ProductID, D.LineTotal FROM Sales.SalesOrderHeader H INNER JOIN Sales.SalesOrderDetail D ON H.SalesOrderID = D.SalesOrderID WHERE H.CustomerID > 100 >> file:///C:/Util/WikidPad/MyWiki/MergeJoin.jpg <<pre SET STATISTICS PROFILE ON SELECT H.CustomerID, H.SalesOrderID, D.ProductID, D.LineTotal FROM Sales.SalesOrderHeader H INNER JOIN Sales.SalesOrderDetail D ON H.SalesOrderID = D.SalesOrderID WHERE H.CustomerID > 100 SET STATISTICS PROFILE OFF >> file:///C:/Util/WikidPad/MyWiki/MergeJoin_grid.jpg

Um Merge join costuma ser mais eficiente e rpido se os dados ordenados puderem ser obtidos a partir de um ndice e pode ser usado com quase todos

os operadores lgicos desde que ao menos um predicado de igualdade esteja envolvido. Tambm suporta mltiplos predicados de igualdade em joins desde que as tabelas de entrada estejam ordenadas em todos os campos envolvidos e na mesma ordem.

A presena de um operador Compute Scalar indica a avaliao de uma expresso para produzir o valor calculado escalar. Na query acima selecionamos \LineTotal que um campo derivado, sendo assim ele foi utilizado no plano de execuo.

*Hash Join*

Um Hash join normalmente utilizado quando as tabelas de entrada so muito grandes e no existem ndices adequados nelas. Um Hash join executado em duas fases; a fase de Build e a fase de Probe (teste) por isso o hash join tem duas entradas ou seja, entrada de build e entrada de probe. A menor das entrada escolhida como a entrada de build (para minimizar as necessidades de memria para armazenar a hash table que vamos falar mais tarde) e obviamente a outra a entrada de probe.

Durante a fase de build, chaves de juno de todos os registros da tabela build so pesquisadas. Hashes so gerados e colocados em uma tabela na memria. Ao contrrio do Merge join, ela bloqueadora (nenhum registro retornado) at este ponto.

Durante a fase de probe, chaves de join de cada registro da tabela de proble so pesquisadas. Novamente hashes so gerados (usando a mesma funo de hash acima) e comparadas com a tabela de hash para encontrar um correspondncia.

A funo de Hash requer grande quantidade de ciclos de CPU para gerar os hashes e recursos de memria para armazenar a tabela de hash. Se a memria for escassa, algumas parties da tabela de hash so transferidadas para a tempdb e sempre que for necessrio (either to probe or to update the contents) ela trazida de volta para o cache. Para obter alta performances, o otimizador pode paralelizar o Hash join para ter melhor

desempenho em relao aos outros joins. Para mais detalhes clique aqui http://blogs.msdn.com/b/craigfr/archive/2006/11/16/parallel-hash-join.aspx .

Existem trs bsicos de hash joins, * Hash Join em memria quando existir memria suficiente para armazenar a tabela de hash * Grace Hash Join no caso da tabela hash no caber na memria e algumas parties irem para o tempdb * Recursive Hash Join quando a tabela for muito grande e o otimizador tem que usar muitos nveis de merge joins. Para mais detalhes clique aqui http://technet.microsoft.com/en-us/library/ms189313.aspx .

No script #3, estamos criando duas tabelas grandes (a partir de tabelas no banco \AdventureWorks tables) sem ndices. Voc pode ver que o otimizador escolhe utilizar Hash Join neste caso. Novamente diferente do Nested Loops join, ele no l a inner table multiplas vezes.

Script #3 - Hash Join <<pre --Create tables without indexes from existing tables --of AdventureWorks database SELECT * INTO Sales.SalesOrderHeader1 FROM Sales.SalesOrderHeader SELECT * INTO Sales.SalesOrderDetail1 FROM Sales.SalesOrderDetail GO

SELECT H.CustomerID, H.SalesOrderID, D.ProductID, D.LineTotal FROM Sales.SalesOrderHeader1 H INNER JOIN Sales.SalesOrderDetail1 D ON H.SalesOrderID = D.SalesOrderID WHERE H.CustomerID = 670 GO >> file:///C:/Util/WikidPad/MyWiki/HashJoin.jpg

<<pre SET STATISTICS PROFILE ON SELECT H.CustomerID, H.SalesOrderID, D.ProductID, D.LineTotal FROM Sales.SalesOrderHeader1 H INNER JOIN Sales.SalesOrderDetail1 D ON H.SalesOrderID = D.SalesOrderID WHERE H.CustomerID = 670 SET STATISTICS PROFILE OFF >> file:///C:/Util/WikidPad/MyWiki/HashJoin_grid.jpg <<pre --Drop the tables created for demonstration DROP TABLE Sales.SalesOrderHeader1 DROP TABLE Sales.SalesOrderDetail1 >>

*Observao*: O SQL Server faz um bom trabalho decidindo qual operador de join utilizar em cada condio. Entender essas condies ajudam a entender o que pode ser feito para melhorar a performance. No recomendado utilizar join hints (usando a clusula OPTION) para forar o SQL Server a utilizar um operador de join especfico (a menos que no haja outra maneira), mas podemos utilizar outros meios como atualizar as estatsticas, criar ndices ou reescrever as querys.

Fonte: http://www.mssqltips.com/sqlservertip/2115/understanding-sql-serverphysical-joins/