Você está na página 1de 17

8/4/2014

DevMedia - Verso para impresso

DevMedia - Verso para impresso

Usando linguagem SQL para gerao de relatrios - Parte 3


UDFs Escalares e Tabulares
De que se trata o artigo Uso de linguagem SQL para criao de relatrios, desde recursos bsicos at os mais avanados. Esta terceira parte de uma srie de artigos e trata do uso de funes criadas pelo usurio, as UDFs. Sendo assim, este artigo ensina recursos de SQL para leitores iniciantes e avanados, como a criao de funes customizadas. Em que situao o tema til Criao de relatrios usando funes customizadas criadas pelo usurio. Resumo Devman Este artigo trata da criao e uso de funes SQL criadas pelo usurio (UDF). So apresentados os dois principais tipos de UDF segundo o padro ANSI-SQL, que so as funes escalares e as tabulares, que so suportadas pela maioria dos SGBDs. O artigo inclui exemplos simples de UDFs criadas em diferentes SGBDs. Ao final, so apresentados exemplos de estimativa de performance de execuo de consultas usando UDFs escalares e tabulares. Voltamos com mais um artigo desta srie. Como j havia mencionado nos artigos anteriores, esta srie se prope a ajudar tanto o leitor iniciante quanto o leitor mais avanado a trabalhar com a linguagem SQL para gerao de relatrios. Nos dois artigos anteriores, vimos o uso de recursos bsicos da linguagem SQL, como clusulas e operadores especiais, e tambm o uso de vises e consultas aninhadas. Mais especificamente: Parte 1: apresenta recursos bsicos da linguagem SQL, como principais clusulas, funes e alguns operadores. Operadores so os elementos que voc utiliza dentro de expresses para definir como voc quer restringir os dados retornados por uma busca. De uma forma geral, os operadores so divididos em seis grupos: aritmticos, comparao, caractere, lgico, conjunto e outros. Parte 2: apresenta recursos da linguagem SQL para gerao de objetos especiais para manipulao dos dados, como vises e consultas aninhadas. O leitor com alguma familiaridade com SQL j deve ter visto tais recursos, por isso acrescentou-se um estudo de performance para auxili-lo a explorar estas tcnicas de forma otimizada. Nesta terceira parte, iremos falar de funes definidas pelo usurio (conhecidas como UDFs,
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 1/17

8/4/2014

DevMedia - Verso para impresso

sigla do ingls User Defined Functions). Elas permitem que o programador crie funes de diferentes tipos que retornem a informao desejada e que possam ser usadas dentro de declaraes SQL. Apenas para ilustrar, o programador pode, por exemplo, criar uma funo que exiba os nomes dos dias da semana em portugus e usar esta funo para preparar um relatrio. UDFs so recursos criados atravs de uma linguagem de programao que uma extenso do SQL. Outros objetos que so criados da mesma forma so os procedimentos armazenados e gatilhos (ou, se preferir, stored procedures e triggers, respectivamente). Por se tratar de uma extenso da linguagem SQL, cada fornecedor de sistemas gerenciadores de bancos de dados (SGBDs) cria a sua prpria linguagem particular. Assim, temos vrios dialetos em matria de linguagem procedural: a Oracle inclui no seu produto o PL/SQL, o SQL Server da Microsoft traz o T/SQL e a IBM usa no DB2 o SQL/PL. Todas elas so parecidas em sua estrutura, mas preciso cuidado na converso dos cdigos, porque as sintaxes acabam apresentando diferenas marcantes. Havamos mencionado nos artigos anteriores que a srie foi criada a partir de uma palestra que apresentei aos meus colegas de trabalho sobre o uso do DB2. Portanto, neste texto usaremos o SQL/PL para criao da maioria das funes e para fins ilustrativos mostrarei apenas um exemplo de UDF sendo criada em outros SGBDs.

Tpicos discutidos neste artigo


Neste artigo apresentaremos os seguintes tpicos: tipos de UDFs; criao de UDFs escalares; como usar UDFs escalares; consideraes sobre performance das UDFs escalares; criao de UDFs tabulares; como usar UDFs tabulares; consideraes sobre performance das UDFs tabulares.

Base de dados e consideraes


Para situarmos os recursos SQL que vamos estudar, preciso ter uma base de dados como amostra. Usaremos nestes artigos uma base com dados fictcios de demanda de produtos farmacuticos. A Figura 1 mostra o modelo desta base.

[abrir im age m e m jane la]

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

2/17

8/4/2014

DevMedia - Verso para impresso

Figura 1. Modelo de dados da base de exemplo

Assumiremos neste artigo que o leitor j est familiarizado com conceitos bsicos de programao, alm de j dominar os conceitos da linguagem SQL apresentados nos artigos anteriores desta srie.

Tipos de UDFs
As UDFs so bastante versteis e existem diferentes tipos de funes para atender as mais variadas necessidades. Definimos o tipo de cada funo conforme o resultado que esta funo retorna ao ser executada. O padro SQL reconhece dois tipos principais, que so suportados pela maioria dos SGBDs relacionais: as funes escalares, que retornam um nico valor de um tipo de dados qualquer (nmeros, cadeia de caracteres, datas, etc); as funes tabulares, que retornam uma tabela, cuja estrutura (campos e tipos de dados) definida dentro da prpria funo e que no tem um limite de registros a serem retornados. Em geral, as UDFs podem ser criadas em SQL ou mesmo em uma linguagem externa ao SGBD, como C, C++, C#, JAVA, PHP, etc. Neste artigo, nos limitaremos a descrever as UDFs criadas via SQL. O leitor interessado em outras possibilidades deve pesquisar informaes sobre a criao de UDFs externas suportadas pelo seu SGBD especfico.

Criao de UDFs escalares


Como o prprio nome diz, as UDFs escalares retornam um nico valor de um tipo de dados predefinido, ou um escalar, como se diz em matemtica. Elas so muito teis quando precisamos encapsular uma lgica de clculo que usada com frequncia. O uso de UDFs escalares oferece vantagens at mesmo para o caso de manuteno de aplicaes. Por exemplo, se a lgica de clculo precisa mudar por uma razo qualquer, o DBA altera apenas o corpo da prpria funo. E no precisa se preocupar com todas as consultas que invocam esta funo. Mas voc pode estar se perguntando: Se um procedimento armazenado tambm pode receber parmetros de entrada e retornar um parmetro de sada, qual a vantagem da UDF escalar?. uma excelente pergunta e a resposta simples. Porque uma UDF, assim como as funes
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 3/17

8/4/2014

DevMedia - Verso para impresso

internas do SGBD, destinada a ser usada dentro de declaraes SQL, como SELECT, INSERT, UPDATE e DELETE. Um procedimento armazenado no pode ser usado desta maneira, porque ele se destina a interagir com a aplicao. A estrutura de uma funo escalar inclui necessariamente a definio do nome da funo, o nome do parmetro de sada e seu tipo de dados. As funes em geral recebem parmetros de entrada, que precisam ter seus tipos de dados definidos tambm. Na Listagem 1, apresentamos a sintaxe para criao de uma UDF escalar simples, tambm conhecida como inline. Grosso modo, esta sintaxe pode ser usada em qualquer SGBD. A limitao que ela s se aplica criao de funes cuja lgica se restrinja a uma nica linha de cdigo (que simbolizamos na listagem como calculo_simples).
Listagem 1. Sintaxe para criao de UDF escalar simples.

C R E A T EF U N C T I O Nn o m e _ d a _ f u n c a o ( a r g u m e n t o 1t i p o _ d e _ d a d o s 1 ,. . .) R E T U R N St i p o _ d e _ d a d o s _ S a i d a R E T U R N( c a l c u l o _ s i m p l e s ) ;

Evidentemente, a criao de UDFs simples uma situao restrita, porque muitas vezes temos que considerar lgicas complexas, com desvios condicionais, etc. Nestes casos, a sintaxe muda para aceitar recursos de programao mais poderosos. A Listagem 2 mostra a sintaxe usada pelo DB2. Existem mais parmetros opcionais especficos deste SGBD que omitimos por questo de simplicidade.
Listagem 2. Sintaxe para criao de UDF escalar no DB2.
C R E A T EF U N C T I O Nn o m e _ d a _ f u n c a o( a r g u m e n t o 1t i p o _ d e _ d a d o s 1 ,. . .) R E T U R N St i p o _ d e _ d a d o s _ S a i d a L A N G U A G ES Q L B E G I NA T O M I C D E C L A R En o m e _ d a _ v a r i a v e lt i p o _ d e _ d a d o s ; . . . ; S E Tn o m e _ d a _ v a r i a v e l=( P r o c e d i m e n t o _ d e _ c a l c u l o ) ; . . . ; R E T U R Nn o m e _ d a _ v a r i a v e l ; E N D

Para ilustrar, vamos estudar como usar UDFs para solucionar um problema que vimos no artigo anterior desta srie: como calcular o primeiro dia do ms anterior. Naquela oportunidade, apresentamos um clculo de datas dentro da prpria declarao SQL. A inteno era ter uma lgica de manipulao de datas que pudesse ser empregada em qualquer SGBD. O primeiro problema daquela abordagem que a lgica um tanto confusa para se apresentar dentro do SELECT. O segundo, muito pior que o anterior, que a lgica falhava quando a consulta fosse usada durante o ms de Janeiro de cada ano. Nestes casos, a consulta retornaria uma mensagem de erro, que seria causada por esta lgica que mencionei. O erro ocorria porque a lgica no testava se o ms considerado era Janeiro. Nesta situao, seria necessrio usar um clculo diferente: mudar o ms para 12 e subtrair 1 unidade do ano. A Listagem 3 mostra a criao da UDF MesAnterior no DB2. A lgica usada identifica o ms correspondente data de referncia, para evitar o problema para clculo de Janeiro,
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 4/17

8/4/2014

DevMedia - Verso para impresso

conforme citei anteriormente. Depois deste teste, feito um clculo para compor a data do ms anterior, concatenando o ano, ms e o dia 1. Para isso, so usadas as funes ANSISQL YEAR(), MONTH(), RIGHT() e CAST(). A funo RIGHT() s foi includa pra se garantir que o ms retornado ter sempre duas posies, tipo MM.
Listagem 3. Definindo a UDF escalar MesAnterior no DB2.
C R E A T EF U N C T I O NM e s A n t e r i o r( d t D a t a R e f e r e n c i ad a t e ) R E T U R N Sd a t e L A N G U A G ES Q L B E G I NA T O M I C D E C L A R Ed t D a t a R e s u l t a n t ed a t e ; I FM O N T H ( d t D a t a R e f e r e n c i a )>1T H E N S E Td t D a t a R e s u l t a n t e= C A S T( Y E A R ( d t D a t a R e f e r e n c i a )| |' ' | |R I G H T (' 0 '| |( M O N T H ( d t D a t a R e f e r e n c i a )-1 ),2 ) | |' 0 1 ' A SD A T E ); E L S E S E Td t D a t a R e s u l t a n t e= C A S T ( ( Y E A R ( d t D a t a R e f e r e n c i a ) 1 ) | |' 1 2 0 1 'A SD A T E ); E N DI F; R E T U R Nd t D a t a R e s u l t a n t e ; E N D

Como eu havia dito, a vantagem da lgica da Listagem 3 que ela pode ser reproduzida em qualquer SGBD. Porm, o DB2 oferece recursos de manipulao de datas que poderiam melhorar significativamente a performance desta funo. Apresentamos esta verso melhorada na Listagem 4. Esta lgica faz exatamente a mesma coisa que a lgica anterior, mas usa as funcionalidades de manipulao de datas do DB2 que nos permite acrescentar/subtrair dias, meses ou anos de uma data de referncia. Com isso temos uma lgica muito mais simples e limpa.
Listagem 4. Outra Verso da UDF escalar MesAnterior para o DB2.
C R E A T EF U N C T I O NM e s A n t e r i o r 2( d t D a t a R e f e r e n c i ad a t e ) R E T U R N Sd a t e R E T U R N( d t D a t a R e f e r e n c i a-1m o n t h+1d a y -d a y ( d t D a t a R e f e r e n c i a )d a y s ) ;

A lgica da Listagem 4 to simples que qualquer pessoa suporia que seu clculo deve ser mais rpido que o da lgica da Listagem 3. Na verdade, mesmo, como veremos mais adiante. Para satisfazer a curiosidade do leitor mais detalhista, vamos repetir a lgica da Listagem 4 para criar a mesma funo no SQL SERVER e no ORACLE. Veja na Listagem 5 a sintaxe para criao da funo no SQL SERVER.
Listagem 5. Reescrevendo a UDF escalar MesAnterior2 no SQL SERVER.
C R E A T EF U N C T I O NM e s A n t e r i o r 2( @ d t D a t a R e f e r e n c i as m a l l d a t e t i m e ) R E T U R N Ss m a l l d a t e t i m eA S B E G I N R E T U R N( d a t e a d d ( d ,1-d a y ( @ d t D a t a R e f e r e n c i a ), d a t e a d d ( m ,1,@ d t D a t a R e f e r e n c i a ) ) ) E N D

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

5/17

8/4/2014

DevMedia - Verso para impresso

Fora as evidentes diferenas de sintaxe, vemos na Listagem 5 alguns detalhes importantes do SQL SERVER: 1. o SGBD no suporta o tipo de dados DATE, que padro ANSI SQL; necessrio usar o tipo SMALLDATETIME; 2. as variveis definidas dentro da funo devem ser precedidas do caractere @; 3. as operaes com datas so realizadas usando-se a funo DATEADD, que usa trs parmetros que especificam, respectivamente, a parte da data tratada (dia, ms, ano, etc), nmero que ser somado data e finalmente a data de referncia. No ORACLE, vamos criar esta funo com a declarao exibida na Listagem 6.
Listagem 6. Reescrevendo a UDF escalar MesAnterior2 no ORACLE.
C R E A T EO RR E P L A C EF U N C T I O NM E S A N T E R I O R 2( d t D a t a R e f e r e n c i ad a t e ) R E T U R Nd a t eI S d t R e t o r n od a t e: =c u r r e n t _ d a t e; B E G I N d t R e t o r n o: =T R U N C ( d t D a t a R e f e r e n c i a-i n t e r v a l' 1 'm o n t h ,' M M ' ) ; R E T U R Nd t R e t o r n o ; E N DM E S A N T E R I O R 2 ; /

Usando a funo TRUNC exibida na Listagem 6 o ORACLE calcula o primeiro dia do ms da data considerada como argumento. Assim, o argumento passado na UDF subtrai um ms da data de referncia e em seguida usa a funo TRUNC. E est pronto!

Como usar UDFs escalares


UDFs so invocadas dentro de declaraes SQL da mesma maneira como fazemos com funes internas do SGBD. Portanto, podemos chamar UDFs dentro de qualquer SQL de manipulao de dados (leitura, insero, alterao e excluso). Assim, vamos retomar um exemplo que usamos no artigo anterior onde apresentamos uma consulta para a identificao do ranking de produtos mais vendidos no ms passado. Esta consulta mostrada na Listagem 7. S pra lembrar, esta lgica de clculo de datas vai falhar durante o ms de Janeiro de cada ano, gerando uma mensagem de erro quando a consulta for executada.
Listagem 7. Relatrio de Demanda por Produto no Ms Anterior.
S E L E C TP . p k P r o d u t o ,P . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R ET . D a t a> =C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )| |' ' | |R I G H T (' 0 '| |( M O N T H ( C U R R E N T _ T I M E S T A M P )-1 ),2 ) | |' 0 1 ' A SD A T E ) A N DT . D a t a<C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )| |' ' | |R I G H T (' 0 '| |( M O N T H ( C U R R E N T _ T I M E S T A M P ) ),2 ) | |' 0 1 ' A SD A T E ) G R O U PB YP . p k P r o d u t o ,P . P r o d u t o ;

Agora vamos reescrever esta consulta usando uma UDF. Obviamente, a sintaxe ser exatamente a mesma independente de usarmos as UDFs MesAnterior ou MesAnterior2, uma vez que ambas usam os mesmo argumentos. Assim,
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 6/17

8/4/2014

DevMedia - Verso para impresso

mostramos na Listagem 8 a chamada da segunda funo, MesAnterior2.


Listagem 8. Usando uma UDF no relatrio de demanda por produtos.
S E L E C TP . p k P r o d u t o ,P . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R ET . D a t a> =M e s A n t e r i o r 2 ( C U R R E N T _ T I M E S T A M P ) A N DT . D a t a< M e s A n t e r i o r 2 ( C U R R E N T _ T I M E S T A M P+1m o n t h ) G R O U PB YP . p k P r o d u t o ,P . P r o d u t o ;

Veja que a sentena da Listagem 8 ficou bastante limpa com uso da UDF MesAnterior2. O nico cuidado foi corrigir o argumento usado na segunda chamada da UDF (data atual mais um ms). Claro que se poderia criar uma segunda UDF para clculo da data final do ms anterior, assim o SQL ficaria ainda mais simples. Apresentamos na Listagem 9 esta nova funo e o relatrio de ranking usando as duas UDFs criadas.
Listagem 9. UDF FimDoMes para o DB2 e seu Uso.
C R E A T EF U N C T I O NF i m D o M e s( d t D a t a R e f e r e n c i ad a t e ) R E T U R N Sd a t e R E T U R N( d t D a t a R e f e r e n c i a-d a y ( d t D a t a R e f e r e n c i a )d a y s ) ;

-U s od e s t af u n on or e l a t r i od er a n k i n g S E L E C TP . p k P r o d u t o ,P . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R ET . D a t aB E T W E E NM e s A n t e r i o r 2 ( C U R R E N T _ T I M E S T A M P ) A N DF i m D o M e s ( C U R R E N T _ T I M E S T A M P ) G R O U PB YP . p k P r o d u t o ,P . P r o d u t o ;

A seguir, apresentamos algumas consideraes sobre performance destas consultas.

Consideraes sobre performance das UDFs escalares


Chegou a hora de avaliar a performance que conseguimos com as diferentes lgicas usadas. Neste teste, pretendemos comparar a consulta da Listagem 7 (que usa um clculo manual de datas) com a da Listagem 8, que trabalha com uma UDF escalar. importante lembrar que as consultas acessam o mesmo banco, buscam dados nas mesmas tabelas e retornam exatamente o mesmo resultado. A maior das tabelas usadas aquela que tem dados de demanda, com cerca 2,1 milhes de registros. Para avaliar a performance, vamos analisar o plano de execuo destas consultas (veja Nota DevMan1). Eu usei o IBM DATA STUDIO, que oferece um recurso grfico de visualizao do plano de execuo de uma consulta, chamado VISUAL EXPLAIN, descrito em detalhes na documentao do DB2 (veja seo Referncias).

Nota Devman 1: Otimizador de Consultas: O plano de execuo de uma consulta o roteiro que define os passos que o mecanismo do SGBD dever realizar para conseguir executar uma consulta.

Este plano pode ser preparado usando-se diferentes estratgias e o usurio pode obter
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 7/17

8/4/2014

DevMedia - Verso para impresso

informaes sobre ele atravs de ferramentas especficas, que retornam informaes em texto e/ou graficamente. Porm, no uma tarefa simples avaliar e decidir qual dos possveis planos de execuo o melhor deles, isto , qual deles tem menor custo de execuo em termos de performance e uso de recursos de hardware. Para isso que os principais SGBDs do mercado dispem de um componente interno muito importante chamado Otimizador de Consultas. este otimizador que avalia estes possveis planos com base em dados estatsticos e define qual deles ser efetivamente usado na execuo da consulta. O usurio at pode influenciar nas escolhas do otimizador, mas no recomendvel faz-lo. Via de regra, mais seguro confiar na escolha do otimizador, a menos que voc saiba exatamente o que est fazendo. As Figuras 2 e 3 mostram o plano de execuo das consultas apresentadas nas Listagens 7 e 8, respectivamente. Primeiramente, vemos que as Figuras 2 e 3 mostram diagramas visivelmente diferentes, mas cujo custo total de execuo praticamente o mesmo: 2.460,47 e 2.469,82, respectivamente. A diferena entre os custos de cada consulta irrisria, menos de 0,4%. Observando-se mais atentamente, notamos que os planos de execuo tm os mesmos passos, eles apenas so executados numa sequncia diferente, como se nota pelo ndice de cada um destes passos.
[abrir im age m e m jane la]

Figura 2. Plano de execuo da Listagem 7.

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

8/17

8/4/2014

DevMedia - Verso para impresso

[abrir im age m e m jane la]

Figura 3. Plano de execuo da Listagem 8.

A Tabela 1 mostra esta sequncia em destaque e calcula o custo de execuo de cada etapa individual, j que os nmeros apresentados pelo VISUAL EXPLAIN representam o custo acumulado de todas as etapas que antecedem um dado passo.
[abrir im age m e m jane la]

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

9/17

8/4/2014

DevMedia - Verso para impresso

Tabela 1. Sequncia e Custo de Cada Passo do Plano de Execuo.

A Tabela 1 traz informaes importantes, pois temos o clculo do custo de cada etapa. Mas observamos tambm que os dois planos de execuo usam exatamente as mesmas operaes, alm de que os custos de cada passo so praticamente os mesmos. Mas mais fcil observar isso na Tabela 2.
[abrir im age m e m jane la]

Tabela 2. Comparativo de Custo Individual por Passo nas Diferentes Consultas.

Note que o nico custo muito diferente o hash join (HSJOIN), pela simples razo de serem executados em momentos diferentes e, portanto, trabalhando com volumes de dados diferentes. Pela mesma razo, a etapa de ordenao de dados (SORT) tambm apresenta alguma diferena. Os demais passos so praticamente idnticos. Por este comparativo vemos que o otimizador de consultas consegue uma boa soluo para ambas as consultas, que acabam apresentando performance muito parecida.
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 10/17

8/4/2014

DevMedia - Verso para impresso

De fato, no se espera que uma UDF seja usada para melhorar performance de uma consulta. No esse o seu propsito. As UDFs se propem a garantir que uma lgica complexa seja repetida consistentemente em diferentes consultas. Porm, necessrio cuidado com a lgica escolhida para uma UDF. Usamos na Listagem 8 uma funo com uma lgica muito simples e otimizada, que foi definida na Listagem 4. O Otimizador de Consultas do DB2 trata as funes como um pacote fechado, uma caixa preta, e no influencia na sua operao. Portanto, a UDF precisa garantir uma boa performance por si s, porque seu contedo no ser otimizado durante a execuo da consulta.

Criao de UDFs tabulares


UDFs tabulares so funes criadas pelo usurio que aceitam parmetros de entrada, uma lgica qualquer e retornam uma tabela como resultado. Se voc continua atento aos conceitos, pode fazer outra pergunta importante: Ok, mas os procedimentos armazenados e as vises tambm podem retornar tabelas, ento qual a vantagem da UDF tabular?. Na realidade, temos duas perguntas aqui. No que diz respeito aos procedimentos armazenados, os SGBDs permitem que se crie tabelas a partir de procedimentos armazenados. Alguns deles permitem at que se retornem variveis de tabela. Mas a vantagem da UDF tabular, mais uma vez, que ela projetada para ser usada dentro de consultas, ao passo que os procedimentos armazenados retornam dados para aplicaes. Quando comparamos as UDFs tabulares com vises, percebemos que as vises oferecem uma performance to boa quanto as prprias tabelas. Mas elas tm uma estrutura fixa e qualquer tipo de manipulao de dados tem que ser feita atravs de consultas sobre a prpria viso. Isso muito til, mas existem situaes em que precisamos ter um controle maior, seja atravs de uma lgica de gerao de dados mais elaborada ou atravs da parametrizao da consulta. E quem nos oferece estas possibilidades so as UDFs tabulares. Apesar da flexibilidade, as UDFs tabulares no oferecem uma boa performance, at porque elas no so avaliadas pelos otimizadores de consultas dos SGBDs. Normalmente, se a UDF retorna apenas um registro, no teremos grande impacto em performance. Mas a coisa muda quando retornamos centenas de registros. Sendo assim, preciso ter critrio e avaliar cuidadosamente se de fato voc precisa de uma UDF tabular ou se uma viso ainda a melhor opo. Feito este comentrio importante, vamos agora ver a sintaxe das UDFs tabulares no DB2, apresentada na Listagem 10.

Listagem 10. Sintaxe para criao de UDF tabular no DB2.


C R E A T EF U N C T I O Nn o m e _ d a _ f u n c a o( a r g u m e n t o 1t i p o _ d e _ d a d o s 1 ,. . .) R E T U R N ST A B L E([ C o l u m n N a m e ][ C o l u m n D a t a T y p e ], . . .)| L A N G U A G ES Q L < C O N T A I N SS Q L|R E A D SS Q LD A T A|M O D I F I E SS Q LD A T A > B E G I NA T O M I C < l g i c ad at a b e l a > ; E N D

Vejamos um exemplo. Imagine que precisamos gerar um relatrio de vendas mensais por produto, mas que uma rotina que precisa ser repetida para todos os produtos da companhia. A ideia termos uma UDF tabular que aceite como parmetros o cdigo do produto e o ano desejado. Mais uma vez, usaremos sintaxe e funes disponveis no DB2. A Listagem 11
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 11/17

8/4/2014

DevMedia - Verso para impresso

mostra esta UDF. Ela define uma funo que retorna uma tabela de quatro campos e ento faz um SELECT filtrando dados de demanda para o ano que informado como parmetro da funo. A questo aqui que se usa novamente uma composio de datas usando a funo CAST().
Listagem 11. Definindo a UDF tabular DemandaAno no DB2.
C R E A T EF U N C T I O ND e m a n d a A n o( @ i n t P r o d u t oI N T ,@ c h Y e a rC H A R ( 4 )) R E T U R N ST A B L E ( c o d P r o d u c tI N T , Y e a rI N T , M o n t hI N T , S a l e sD e c i m a l ( 9 , 2 ) ) L A N G U A G ES Q L R E A D SS Q LD A T AD E T E R M I N I S T I CN OE X T E R N A LA C T I O N B E G I NA T O M I C R E T U R N S E L E C Tf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) , S U M ( V a l o r R e a l )A SS a l e s F R O Mt b l D e m a n d a W H E R Ef k P r o d u t o=@ i n t P r o d u t o A N DD a t aB E T W E E NC A S T ( ( @ c h Y e a r| |0 1 0 1 )A SD A T E ) A N DC A S T ( ( @ c h Y e a r| |1 2 3 1 )A SD A T E ) G R O U PB Yf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) ; E N D

Via de regra, no uma boa ideia tratar datas como caracteres, assim como fizemos na Listagem 11. Esta prtica geralmente tem um impacto maior no desempenho da consulta do que se usssemos funes que lidam com datas e nmeros. Uma alternativa seria reescrever esta funo, mudando o parmetro de entrada @chYear para uma data de referncia e substituir as chamadas funo CAST (de converso de dados) por clculos do primeiro e do ltimo dia do ano para aquela data de referncia. Com estas informaes, apresentamos a nova UDF na Listagem 12. A grande diferena aqui que se usa novamente as funcionalidades do DB2 para manipulao de datas, tornando a declarao SQL muito mais limpa. Em outros SGBDs, a sintaxe e as funes so um tanto diferente. A seguir, a Listagem 13 apresenta a reproduo desta mesma lgica para uma UDF tabular criada no SQL SERVER.
Listagem 12. Outra verso da UDF tabular DemandaAno no DB2.
C R E A T EF U N C T I O ND e m a n d a A n o 2( @ i n t P r o d u t oI N T ,@ d t R e f e r e n c i aD A T E ) R E T U R N ST A B L E ( c o d P r o d u c tI N T , Y e a rI N T , M o n t hI N T , S a l e sD e c i m a l ( 9 , 2 ) ) L A N G U A G ES Q L R E A D SS Q LD A T AD E T E R M I N I S T I CN OE X T E R N A LA C T I O N B E G I NA T O M I C D E C L A R E@ d t I n i c i a lD A T E; D E C L A R E@ d t F i n a lD A T E;

S E T@ d t I n i c i a l=@ d t R e f e r e n c i a -d a y o f y e a r ( @ d t R e f e r e n c i a )d a y s+1d a y;

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

12/17

8/4/2014
S E T@ d t F i n a l

DevMedia - Verso para impresso


=@ d t R e f e r e n c i a

-d a y o f y e a r ( @ d t R e f e r e n c i a )d a y s+1y e a r ; R E T U R N S E L E C Tf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) , S U M ( V a l o r R e a l )A SS a l e s F R O Mt b l D e m a n d a W H E R Ef k P r o d u t o=@ i n t P r o d u t o A N DD a t aB E T W E E N@ d t I n i c i a lA N D@ d t F i n a l G R O U PB Yf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) ; E N D

Listagem 13. Reescrevendo a UDF tabular DemandaAno2 no SQL SERVER.


C R E A T EF U N C T I O ND e m a n d a A n o 2 ( @ i n t P r o d u t oI N T ,@ d t R e f e r e n c i aS M A L L D A T E T I M E ) R E T U R N S@ t m p R e s u l t a d oT A B L E ( c o d P r o d u c tI N T , Y e a rI N T , M o n t hI N T , S a l e sD e c i m a l ( 9 , 2 ) )A S B E G I N D E C L A R E@ d t I n i c i a lS M A L L D A T E T I M E; D E C L A R E@ d t F i n a lS M A L L D A T E T I M E;

S E T@ d t I n i c i a l=D A T E A D D ( D ,( 1-D A T E P A R T ( D Y ,@ d t R e f e r e n c i a ) ) , @ d t R e f e r e n c i a ) ; S E T@ d t F i n a l=D A T E A D D ( Y ,1 ,D A T E A D D ( D , ( d b o . D A Y S I N Y E A R ( @ d t R e f e r e n c i a ) -D A T E P A R T ( D Y ,@ d t R e f e r e n c i a ) ),@ d t R e f e r e n c i a ) ) ;

I N S E R TI N T O@ t m p R e s u l t a d o S E L E C Tf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) , S U M ( V a l o r R e a l )A SS a l e s F R O Mt b l D e m a n d a W H E R Ef k P r o d u t o=@ i n t P r o d u t o A N DD a t aB E T W E E N@ d t I n i c i a lA N D@ d t F i n a l G R O U PB Yf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) ;

R E T U R N E N D

Talvez a diferena mais importante entre as sintaxes do DB2 e SQL SERVER que neste ltimo precisamos definir uma varivel de tabela (@tmpResultado) e inserir registros nela. Veja que definimos esta varivel no incio da funo e ao final no fechamento da funo, quando aparece a palavra reserva RETURN, nem preciso informar que ela a tabela retornada, pela simples razo de que a funo s pode retornar um nico objeto tabela. Essa a sintaxe do SQL SERVER para funes tabulares que incluem vrias declaraes. A sintaxe mais simples quando se trata de funes de uma nica declarao (as funes inline). No caso do ORACLE, o processo mais complexo. So necessrios alguns passos intermedirios, como a criao de um tipo de dados que retorne um objeto. O processo como um todo tem uma estrutura bastante diferente dos DB2 ou SQL SERVER, alm de ter um processamento diferente tambm. Deixamos para o leitor mais curioso checar na seo Referncias as instrues sobre como proceder para criao de UDFs tabulares no ORACLE.

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

13/17

8/4/2014

DevMedia - Verso para impresso

Como usar UDFs tabulares


As UDFs tabulares so invocadas de uma maneira diferente conforme o SGBD. No DB2 e no ORACLE necessrio informar ao SGBD que aquela UDF precisa ser tratada como uma tabela. E isto feito atravs do operador TABLE(). O SQL SERVER dispensa o uso de qualquer operador. A Listagem 14 mostra um exemplo desta chamada e a Tabela 3 apresenta o resultado obtido.
Listagem 14. Invocando a UDF tabular DemandaAno2 no DB2.
S E L E C T* F R O MT A B L E ( D e m a n d a A n o 2 ( 2 2 1 7 2 0 ,C U R R E N T _ D A T E ) ) O R D E RB Y1 , 2 , 3 ;

[abrir im age m e m jane la]

Tabela 3. Resultado da consulta da Listagem 15.

Consideraes sobre performance das UDFs Tabulares


Agora vamos tratar de performance das UDFs tabulares, que um caso mais delicado. Iremos comparar a performance obtida usando-se a UDF, como vemos na Listagem 14, com a performance obtida numa consulta direta sobre as tabelas originais. Para ser mais justo nesta comparao, faremos o clculo das datas de incio e fim do ano considerando-se uma data de referncia, assim como se calcula dentro da UDF. Pondo isso tudo para funcionar numa declarao SQL, chegamos ao SELECT que apresentamos na Listagem 15.
Listagem 15. Consulta direta s tabelas para clculo de demanda anual.
S E L E C Tf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) , S U M ( V a l o r R e a l )A SS a l e s F R O Mt b l D e m a n d a W H E R Ef k P r o d u t o=2 2 1 7 2 0 A N DD a t aB E T W E E NC U R R E N T _ D A T E-d a y o f y e a r ( C U R R E N T _ D A T E )d a y s+ 1d a y

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

14/17

8/4/2014

DevMedia - Verso para impresso


A N DC U R R E N T _ D A T E-d a y o f y e a r ( C U R R E N T _ D A T E )d a y s+ 1y e a r G R O U PB Yf k P r o d u t o ,Y E A R ( D a t a ) ,M O N T H ( D a t a ) O R D E RB Y1 , 2 , 3 ;

As consultas exibidas nas Listagens 14 e 15 usam os mesmos parmetros de cdigo de produto e data e retornam exatamente o mesmo resultado, que o apresentado na Tabela 3. Feitas as consideraes, vamos ao que interessa. Para comear, vejamos os planos de execuo destas consultadas apresentados nas Figuras 4 e 5.
[abrir im age m e m jane la]

Figura 4. Plano de execuo da Listagem 14.

[abrir im age m e m jane la]

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

15/17

8/4/2014

DevMedia - Verso para impresso

Figura 5. Plano de execuo da Listagem 15.

Analisando a Figura 5, vemos que o plano de execuo da consulta tem um custo baixo: 262,18. Por este nmero, entendemos que a consulta est bem otimizada e tem um bom desempenho. Porm, quando olhamos a Figura 4 com mais ateno, notamos que ela mostra um custo surpreendentemente baixo: 15,1439. Este nmero realmente muito estranho. Ele sugere que a performance com a UDF tabular muito melhor do que a consulta direta, o que no verdade! O que acontece que a UDF tabular tratada como um bloco e o que vemos no plano de execuo no inclui o custo de execuo da UDF. Para verificar este comportamento, basta checar no DATA STUDIO o tempo de execuo da consulta. As Figuras 6 e 7 mostram estes resultados.

[abrir im age m e m jane la]

Figura 6. Tempo de execuo de consulta da Listagem 14.

Agora sim temos nmeros mais representativos! A consulta direta roda em 734 milissegundos, enquanto que a consulta com a UDF tabular roda em 6s 422 milissegundos, ou seja, 775% mais tempo!
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307 16/17

8/4/2014

DevMedia - Verso para impresso

Portanto muito cuidado ao se usar UDFs tabulares. Alm de terem um impacto importante na performance, muitas vezes as informaes que temos a seu respeito mascaram a sua performance real, que pode facilmente levar a decises desastrosas.
[abrir im age m e m jane la]

Figura 7. Tempo de execuo de consulta da Listagem 15.

Concluso
Vimos aqui informaes bsicas sobre a criao, uso e performance de UDFs. UDFs so recursos muito interessantes e teis, pois permitem ao usurio criar funes customizadas que atendam necessidades especficas de uma aplicao. E ainda oferecem a facilidade de poder retornar variveis de diferentes tipos de dados (inteiros, caracteres, datas, tabelas, etc). Mas as UDFs devem ser usadas com cuidado, especialmente as UDFs tabulares. necessrio muito cuidado com otimizao do cdigo das UDFs durante a fase de desenvolvimento, pois como mostramos aqui, uma vez criada, a UDF tratada como uma caixa-preta pelo otimizador de consultas do SGBD. No prximo artigo, vamos estudar as expresses de tabela (conhecidas como CTEs Common Table Expressions), recursos muito interessantes e poderosos e que permitem inclusive operao de clculos recursivos dentro de consultas SQL. At l!

Wagner Crivelini
Engenheiro formado pela UNICAMP, consultor em TI com 15 anos de experincia, particularmente em projetos de Business Intelligence. Atualmente trabalha na IBM, onde atua como DBA em projeto internacional.

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4307&revista=impressao_96#a-4307

17/17