Social Icons

28 de out. de 2010

Cargas de dados mais rápidas com o SQL Loader


Olá Pessoal,

     No artigo de hoje iremos falar sobre o SQL Loader, um utilitário que permite ler dados de arquivos externos e carregar estes dados em tabelas de um Banco de Dados Oracle, com a vantagem de efetuar cargas de dados mais rápidas que os caminhos de atualização de dados convencionais, tais como scripts de INSERT.

     O SQL Loader pode ser instalado através do instalador do Oracle Client e seu arquivo utilitário, sqlldr.exe, encontra-se na pasta "ORACLE_HOME\<versão do cliente>\bin".
      Ex.: "C:\Oracle\Produto\Cliente\10gR2\BIN\sqlldr.exe".

     Para executar uma carga de dados com o utilitário do SQL Loader , deve-se utilizar obrigatoriamente, como parâmetros, um arquivo de controle e um arquivo de dados. Opcionalmente, a carga de dados pode gerar log das operações executadas, dos dados rejeitados e dos dados descartados.

     O arquivo de controle é um arquivo texto com uma extensão .ctl (preferencial, mas não obrigatória), que deve conter as seguintes informações: caminho e nome do arquivo de dados, formato dos dados, detalhes de configurações e como manipular os dados.

     O arquivo de dados é um arquivo texto com uma extensão qualquer (.csv, .dat, .txt etc.), que poderá conter registros (linhas) em um dos seguintes formatos: registro fixo, registro variável e registro de fluxo.
   
    O arquivo de log é um arquivo texto que contém um resumo detalhado do processo de carga.
   
    O arquivo de dados rejeitados ou arquivo de erros (bad file), contém registros que são rejeitados pelo processo de carga por conterem dados em formato de entrada inválido. Ele permite verificar quais linhas do arquivo de dados foram rejeitadas, para que você possa posteriormente analisar a causa da rejeição.

     O arquivo de dados descartados é criado somente quando for especificado no arquivo de controle e contém registros que são excluídos do processo de carga por não corresponderem aos critérios de seleção de carga, especificados no arquivo de controle.

     Na Imagem 01 abaixo, podemos visualizar todos os itens citados citados acima e como eles interagem com o utilitário do SQL Loader:
 
Imagem 01 - Diagrama da Estrutura do SQL Loader
 Fonte: Oracle Corporation
     
   
    Neste artigo não explicarei todos os detalhes do SQL Loader. Meu objetivo é apenas apresentar uma visão geral e demonstrar seu desempenho (através de um exemplo).

    Para verificar o desempenho do SQL Loader, criaremos os seguintes objetos e arquivos:
   
        1- Uma tabela CLIENTES em um Banco de Dados Oracle com um usuário que tenha privilégios para criar tabelas em seu próprio schema:
       
            CREATE TABLE cliente
           (
               cod_cliente NUMBER,
               nom_cliente VARCHAR2(50),
               dat_nascimento DATE,
               dat_inclusao DATE
           )

               
        2- Um arquivo de controle com o nome clientes.ctl, que pode ser baixado a partir do Meu Sky Drive (ver painel inferior direito), pasta Oracle -> Scripts, arquivo clientes.zip.
            
             Neste arquivo de controle foram parametrizados os seguintes valores:
                - OPTIONS (SILENT=ALL, DIRECT=TRUE):
                     Suprime todas as mensagens de feedback durante a execução da carga e faz inserção em modo DIRECT PATH (mais rápido).
                - UNRECOVERABLE LOAD DATA:
                     Não gera redo log.
                - CHARACTERSET WE8ISO8859P1:
                     Utiliza character set WE8ISO8859P1.
                - TRUNCATE:
                     Trunca dados da tabelas antes de iniciar a inserção dos dados.
                - FIELDS TERMINATED BY '|':
                     Utiliza o caractere "|" como delimitador de colunas.
                - OPTIONALLY ENCLOSED BY '"'
                     
Indica que o caractere " (aspas duplas) pode ser utilizado opcionalmente como delimitador de valores.

                - cod_eleitor SEQUENCE(Max):
                     Insere código sequencial na coluna "cod_eleitor".
                - dat_nascimento "TO_DATE (:dat_nascimento, 'dd/mm/yyyy')":
                     Converte data de nascimento (coluna dat_nascimento), recuperada do arquivo de dados, no formato 'dd/mm/yyyy'.
                - dat_inclusao SYSDATE:
                     Insere data/hora atual na coluna inclusão.
           
        3- Um arquivo de dados no formato de registro variável, com o nome clientes.txt. Crie o arquivo com 254.000 linhas repetindo o conteúdo das 2 linhas abaixo:
           
            "Homer Simpson"|"06/08/1910"
            "Marge Simpson"|"23/10/1914"
 
  
        Obs.: Crie os arquivos clientes.ctl e clientes.txt na mesma pasta.
 
        4- Após criar os objetos e arquivos dos passos anteriores, abra uma janela de comandos do Sistema Operacional, entre na pasta em que você criou os arquivos e digite o comando abaixo, substituindo XXX e ZZZ pelo nome e senha do usuário que criou a tabela e YYY pelo nome da instância de Banco de Dados em que a tabela foi criada:
             sqlldr userid=XXX@YYY/ZZZ control=clientes.ctl log=clientes.log

        O comando acima irá ler o arquivo de controle clientes.ctl e se tudo estiver OK, irá iniciar o processo de carga e gerar um arquivo de log com o nome clientes.log.      

        Para efeitos de comparação de performance entre um processo de carga executado pelo SQL Loader e um processo de carga executado por um script de comandos INSERT, seguem abaixo os resultados de um teste que eu fiz:

     TESTE 1- Carga de dados de 254.000 registros via SQL Loader utilizando o exemplo deste artigo:
                Tempo de execução: 04 segundos.

     TESTE 2- Carga de dados de 254.000 registros via SQL Plus executando um script de comandos INSERT:
                Tempo de execução: 12 minutos e 25 segundos.

        Neste teste (conforme os parâmetros configurados) tivemos um mega ganho (18.625% superior) de desempenho no tempo de execução da carga utilizando o SQL Loader.


COMENTÁRIOS FINAIS:
     Através dos resultados dos testes que eu fiz utilizando o exemplo deste artigo, conseguimos verificar que o SQL Loader é uma ótima ferramenta para ser utilizada para efetuar cargas de dados quando a origem dos dados é um arquivo externo, em formato texto.

     Para mais informações, leia o FAQ oficial da Oracle e as referências deste artigo.


Referências:
 - SQL*Loader (sqlldr) Utility tips: http://www.dba-oracle.com/tips_sqlldr_loader.htm
 - Oracle SQL*Loader: http://www.psoug.org/reference/sqlloader.html
 - Oracle SQL*Loader Overview: http://www.oracle.com/technology/products/database/utilities/htdocs/sql_loader_overview.html
 - SQL*Loader Command-Line Reference: http://www.csee.umbc.edu/help/oracle8/server.815/a67792/ch06.htm
 - SQL*Loader Control File Reference: http://www.cs.umbc.edu/help/oracle8/server.815/a67792/ch05.htm
 - Treinamento oficial da Oracle "Oracle Database 10G Administration Workshop I".

22 de out. de 2010

Scripts Tablespaces


Olá Pessoal,

     Nesta semana, estou compartilhando scripts para consultar dados sobre tablespaces de um Banco de Dados Oracle. Os scripts permitem:

         - Consultar informações sobre tamanho total, espaço livre, espaço usado etc.;
         - Consultar informações sobre extents utilizados dos tablespaces;
         - Consultar informações sobre segmentos utilizados dos tablespaces;
         - Verificar tablespaces fragmentados.


      Para fazer download dos scripts (arquivo scripts_tablespaces.zip), acessem a pasta Oracle/Scripts, em Pastas Públicas, no MEU SKY DRIVE.


Até semana que vem!

19 de out. de 2010

Ressetando Sequências no Oracle


Pessoal,

     Uma problema muito comum que os desenvolvedores que trabalham com Bancos de Dados Oracle enfrentam, ao testar suas aplicações em ambientes de Desenvolvimento e Homologação, é a impossibilidade de ressetar ou redefinir valores de sequências (sequences) após terminar testes que necessitam limpar ou voltar o estado anterior dos dados afetados.
    
     No Oracle, as sequências não podem ser ressetadas ou redefinidas para um determinado valor. Para ressetar (determinar ou reatribuir o valor inicial), por exemplo, uma sequência que tem o valor de início 1, que termina em 1000 e que tem o valor atual de 353, o único meio é configurar reciclagem de valores e chamar o método NEXTVAL da sequence inúmeras vezes até que ela chegue ao número final (1000) + 1.

     Como este processo é bem trabalhoso, muitos DBA´s apenas apagam e recriam as sequências, o que é não é um método muito seguro, pois neste processo, ao apagar a sequência, todos os usuários que possuíam privilégios de acesso sobre ela, perdem estes privilégios. Para evitar este problema e facilitar o trabalho dos desenvolvedores e/ou DBA´s, podemos criar a procedure abaixo, dar privilégio de EXECUTE nela para os desenvolvedores que precisam ressetar suas sequências e depois instruí-los a chamar esta procedure passando apenas o nome do owner da sequência e o nome da própria sequência.
        Ex.: BEGIN
                SP_SEQUENCE_RESET(SCHEMA_NAME, SEQUENCE_NAME);
             END;

               
--- ínicio do código da procedure
create or replace PROCEDURE SP_SEQUENCE_RESET(schema_name VARCHAR2, sequence_name VARCHAR2)
AUTHID current_user is
BEGIN
--------------------------------------------------------------------------------
--  SP_SEQUENCE_RESET
--------------------------------------------------------------------------------
-- PARÂMETROS
--------------------------------------------------------------------------------
-- entrada: schema_name ->  nome do schema proprietário da sequence a ser resetada
-- entrada: sequence_name -> nome da sequence a ser resetada
--------------------------------------------------------------------------------
-- Criação: 19/10/2010
-- Autor: Fábio Prado
-- Descrição: Procedure para ressetar sequences
-- Detalhes: Utiliza os privilégios do usuário que está chamando a procedure (AUTHID current_user).
-- O usuário que chama a procedure deve ter privilégios para selecionar e alterar a sequence informada.
--------------------------------------------------------------------------------
    DECLARE plast_number number;
            PCYCLE_FLAG CHAR(1);
            pmin_value NUMBER;
            pmax_value NUMBER;
            psequence_name VARCHAR2(30);
            powner_name VARCHAR2(30);
            pstrSQL VARCHAR2(1000);
            pseq_number number;
    BEGIN
        BEGIN       
            powner_name:=UPPER(schema_name);
            psequence_name:=UPPER(sequence_name);          

            BEGIN
            --1) Testa sequência para ver se ela já foi inicializada, para evitar erro ORA-08002
            PSTRSQL:='SELECT ' || POWNER_NAME || '.' || PSEQUENCE_NAME || '.CURRVAL FROM DUAL';
            --dbms_output.put_line(pstrSQL);

            EXECUTE IMMEDIATE pstrSQL INTO pseq_number;
            EXCEPTION
              WHEN OTHERS THEN
                -- Entra nesse erro quando sequence já estiver no valor limite
                IF INSTR(UPPER(SQLERRM(SQLCODE)),'ORA-08004') <> 0 THEN
                  -- nao faz nada, só trata erro para continuar processamento
                  NULL;
                END IF;            
            END;

            --2 ) Verifica qual o último valor registrado na seqüência com a seguinte instrução.
            SELECT  MIN_VALUE, MAX_VALUE, CYCLE_FLAG, LAST_NUMBER
            into    pmin_value, pmax_value, pcycle_flag, plast_number
            from    all_sequences d
            where   d.sequence_owner = UPPER(powner_name)
            AND     d.sequence_name = UPPER(psequence_name);

            dbms_output.put_line('Valor atual da sequência: ' || (plast_number));
 
            --3) se número atual da sequence é maior que maxvalue entao iguala valores
            IF plast_number > pmax_value THEN
              pmax_value:= plast_number;
            END IF;

            --4) Altera o minvalue para zero e maxvalue para o mesmo valor encontrado no last_value no resultado da instrução acima.
            pstrSQL:='alter sequence ' || powner_name || '.' || psequence_name || ' minvalue 0 maxvalue ' || plast_number || ' cycle';
            dbms_output.put_line(pstrSQL);
            EXECUTE IMMEDIATE pstrSQL;

            --5) Executa o Nextval múltiplas vezes até valor da sequencia for igual valor inicial
            WHILE (pseq_number <> pmin_value) LOOP
                PSTRSQL:='SELECT ' || POWNER_NAME || '.' || PSEQUENCE_NAME || '.NEXTVAL FROM DUAL';
                --dbms_output.put_line(pstrSQL);
                EXECUTE IMMEDIATE pstrSQL INTO pseq_number;       
            END LOOP;           

            --6) Reatribui valores originais de minvalue, maxvalue e cache da sequencia
            IF PCYCLE_FLAG = 'N' THEN
                pstrSQL:='alter sequence  ' || powner_name || '.' || psequence_name || ' minvalue ' || pmin_value || ' maxvalue ' || pmax_value || '  nocycle';
            ELSE
                pstrSQL:='alter sequence  ' || powner_name || '.' || psequence_name || ' minvalue ' || pmin_value || ' maxvalue ' || pmax_value;
            END IF;
            dbms_output.put_line(pstrSQL);
            EXECUTE IMMEDIATE pstrSQL;   

            DBMS_OUTPUT.PUT_LINE('Procedimento executado com sucesso');
            COMMIT;
        END;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            dbms_output.put_line('Procedimento cancelado: O nome da sequência ' || powner_name || '.' || psequence_name || ' não existe.');
        WHEN OTHERS THEN
            IF INSTR(UPPER(SQLERRM(SQLCODE)),'ORA-08002') <> 0 OR
                INSTR(UPPER(SQLERRM(SQLCODE)),'ORA-04004') <> 0 THEN
                dbms_output.put_line('Procedimento cancelado: Não foi possível ressetar a sequência ' || powner_name || '.' || psequence_name || ' não inicializada.');
            ELSE
                dbms_output.put_line('Erro ao ressetar a sequência ' || powner_name || '.' || psequence_name || ': ' || SQLERRM);
            END IF;
    END;
END;


    Obs.: A procedure, após executada, não altera as configurações (cache, order, cycle etc.) da SEQUENCE. Para ressetar uma sequência é necessário que o usuário que está chamando a procedure tenha privilégios de SELECT e ALTER na sequência informada.

13 de out. de 2010

Scripts Tabelas


Pessoal,

     Nesta semana, estou compartilhando scripts para consultar dados sobre tabelas de um Banco de Dados Oracle. Os scripts permitem:

         - Consultar estatísticas das tabelas: total de linhas, tamanho médio das linhas, tamanho da tabela etc.;
         - Consultar informações sobre a marca d´água (high water) de tabelas de um schema;
         - Consultar tabelas que não possuem chave-primária (PK).
         - Consultar tabelas que não possuem índices.


      Para fazer download dos scripts (arquivo scripts_tabelas.zip), acessem a pasta Oracle/Scripts, em Pastas Públicas, no MEU ONE DRIVE. O arquivo está protegido com senha, Para obtê-la assine a newsletter que encontra-se no painel direito deste blog.


Até a próxima semana!

Salários DBA Oracle


Pessoal,

     Para quem quer ingressar na carreira de DBA Oracle ou para quem tem apenas curiosidade sobre os valores dos salários desta carreira, seguem abaixo, tabelas contendo os valores médios e maiores salários de DBA´s Oracle Júnior e Senior, conforme dados de pesquisas do site Curriculum:
     

Fonte: http://www.curriculum.com.br - 13/10/2010 às 17:50h
 

     Para encontrar informações mais atualizadas sobre salários de um DBA, sugiro também a leitura dos artigos:
           - A carreira de um DBA;
           - Pesquisa salarial de TI;
           - Vídeo sobre a Carreira de um DBA.

     Para aqueles que querem também, compreender o que faz um DBA, sugiro a leitura do artigo: Tarefas de um DBA - O que faz um DBA?.

[]s

 
        
Referências:
     - http://www.curriculum.com.br

5 de out. de 2010

Scripts PGA e SGA


Pessoal,

     Nesta semana, estou compartilhando scripts para consultar as áreas de memória da PGA e SGA.
  
     Os scripts permitem:
         -  Consultar informações de redimensionamento da SGA (quando ASMM estiver habilitada);
         -  Verificar total de memória, total de memória usada e percentual de memória livre de cada área de memória da SGA (large pool, shared pool etc.), inclusive o total da SGA;
         - Consultar estatisticas de consumo de memória da PGA por sessão.

      Para fazer download dos scripts (arquivo scripts_pga_sga.zip), acessem a pasta Oracle/Scripts, em pastas públicas, no MEU SKY DRIVE. Para descompactar é necessário informar uma senhaPara obtê-la assine a newsletter que encontra-se no painel direito deste blog.

Até a próxima!

4 de out. de 2010

Expressões regulares no Oracle Database



    Uma expressão regular (regexp) é uma sequência de caracteres compostos de literais e meta caracteres que descrevem um padrão em um texto. Expressões regulares são úteis para realizar pesquisas e manipulações de strings e podem ser usadas para reforçar CHECK CONSTRAINTs.

    Expressões Regulares estão disponíveis no Oracle Database a partir da versão 10G e são implementadas de acordo com o padrão POSIX para ASCII, através de 4 funções: REGEXP_LIKE, REGEXP_REPLACE, REGEXP_INSTR e REGEXP_SUBSTR.

    Segue abaixo a lista de alguns dos meta-caracteres mais utilizados em regexp:
       - \ : Caractere de escape -> trata o próximo caractere como um literal na expressão
       - * : Quantificador estrela -> combina zero ou mais ocorrências de uma subexpressão precedendo o meta caractere.
       - . : Ponto -> combina qualquer caractere.
       - + : Quantificador mais -> combina uma ou mais ocorrências da subexpressão precendendo o caractere meta.
       - ^ : Início de âncora de linha -> combina a próxima expressão quando ela ocorre no início de uma linha.
       - $ : Fim de âncora de linha -> combina a expressa precedente somente quando ela ocorre no final de uma   linha.
       - [...] : Lista de caracteres de combinação -> combina qualquer caractere na lista.
       - [^...] : Lista de caracteres que não combinam -> combina qualquer caractere que não está na lista.
       - ? : Quantificador de marca de questão -> combina zero ou uma ocorrência de uma subexpressão    precedendo o meta caractere.
       - {m} : Intervalo -> combina exatamente m ocorrências do caractere.
       - {m,} : Intervalo -> combina no mínimo m ocorrências do caractere.
       - {m,n} : Intervalo -> combina no mínimo m ocorrência do caractere e no máximo n ocorrências da subexpressão precedente.
       - \n : Referencia de volta -> combina a nth subexpressão precedente, where n é um inteiro de 1 a 9
       - | : Operador OR -> combina ambos os caracteres ou palavras.
       - (...) : Subexpressão ou agrupamento -> combina uma expressão como uma unidade.
      - [:class:] : Classe de caracteres POSIX -> combina qualquer caractere pertencendo a uma classe especificada de caracteres.

    Segue abaixo um exemplo, passo-a-passo, de uma consulta com regexp utilizando a função REGEXP_LIKE:
   
    PASSO 1: Criando a tabela CLIENTE:
          CREATE TABLE CLIENTE              ( ID        NUMBER,               NOME      VARCHAR2(50),               DT_NASC   CHAR(8));

    PASSO 2: Inserindo dados na tabela CLIENTE:
        INSERT INTO CLIENTE (ID, NOME, DT_NASC) VALUES (1, 'FÁBIO PRADO', '19780101');
        INSERT INTO CLIENTE (ID, NOME, DT_NASC) VALUES (2, 'CHUCK NORRIS', '19500230');
        INSERT INTO CLIENTE (ID, NOME, DT_NASC) VALUES (3, 'HOMMER SIMPSON', '9b420431');
        INSERT INTO CLIENTE (ID, NOME, DT_NASC) VALUES (4, 'FRED FLINSTONE', 'a1820331');
        INSERT INTO CLIENTE (ID, NOME, DT_NASC) VALUES (5, 'ELVIS PRESLEY', '195c0513');
        COMMIT;


    PASSO 3: Utilizando regexp para efetuar uma consulta na tabela CLIENTE para retornar somente registros com datas cadastradas com 8 dígitos e contendo somente caracteres numéricos:
        
                    SELECT     NOME,
                                        DT_NASC
                    FROM       CLIENTE
                    WHERE     REGEXP_LIKE(DT_NASC,'^[[:digit:]]{8}$');


    Obs.: :digit: é uma classe de caracteres POSIX. {8} indica o tamanho da expressão que antecede esse valor. 
                          
    RESULTADO:
               NOME                                               DT_NASC 
                 ---------------------------------------         -----------
                 FÁBIO PRADO                              19780101
                 CHUCK NORRIS                          19500230



   O mais díficil em utilizar expressões regulares é montar a expressão com os meta-caracteres. Para te ajudar neste trabalho, sugiro o site TESTE DE REGEXP (EXPRESSÕES REGULARES). Nele você poderá testar suas expressões regulares e você também encontrará alguns exemplos muito úteis, tais como, expressões para validar e-mail, telefone e URL.

  
COMENTÁRIOS FINAIS:
     Expressões regulares são muito poderosas e permitem efetuar qualquer padrão de pesquisa, porém avalie muito bem a sua utilização. Se forem mal utilizadas poderão ser muito lentas  e consequentemente, poderão degradar a performance da instrução SQL.


REFERÊNCIAS:
   - Treinamento oficial Oracle Database 10g: SQL Fundamentals Part 2
   - Função REGEXP_LIKE:   
            http://support.cs.nott.ac.uk/help/docs/databases/oracle/standard/server.101/b10759/conditions018.htm
   - Oracle Regular Expressions: http://www.psoug.org/reference/regexp.html

1 de out. de 2010

Cláusula WITH (para tunar queries)


     Pessoal, segue abaixo um pequeno tutorial e exemplo de como utilizar a cláusula WITH no Oracle Database.

    A cláusula WITH, existente no Oracle Database a partir da versão 9i release 2, é genericamente conhecida como Commom Table Expression (CTE) e faz parte do padrão ANSI SQL 99. Ela pode ser utilizada para otimizar a performance de consultas SQL , possibilitando a reutilização de blocos de subquery ou tabelas que são referenciadas N vezes dentro da mesma query, criando uma espécie de tabela temporária. Essa tabela temporária existe somente no escopo da instrução SQL em que a cláusula WITH está contida e ela é armazenada em memória ou em um tablespace temporário, que possui acesso mais rápido que um tablespace comum.

    A cláusula WITH permite a redução do uso de recursos do Banco de Dados ao executar queries complexas ou remotas que referenciam na mesma instrução uma ou mais tabelas, N vezes. Isso é muito comum em queries que geram relatórios e que possuem muitas subqueries. Segue abaixo 1 exemplo de query que consulta dados no schema de exemplo HR do Oracle 10G, alterada para utilizar a cláusula WITH.
   
    1- QUERY ORIGINAL:    

        SELECT         D.DEPARTMENT_NAME,
                               SUM(E.SALARY) AS DEPT_TOTAL
        FROM            HR.EMPLOYEES E
        INNER JOIN  HR.DEPARTMENTS D
                ON          E.DEPARTMENT_ID = D.DEPARTMENT_ID
        GROUP BY    D.DEPARTMENT_NAME
        HAVING        SUM(E.SALARY)   >  (
                                              SELECT  SUM(DEPT_TOTAL)/COUNT(*)
                                              FROM    (
                                                        SELECT      D.DEPARTMENT_NAME,
                                                                           SUM(E.SALARY) AS DEPT_TOTAL
                                                        FROM        HR.EMPLOYEES E
                                                        INNER JOIN  HR.DEPARTMENTS D
                                                            ON        E.DEPARTMENT_ID = D.DEPARTMENT_ID
                                                        GROUP BY    D.DEPARTMENT_NAME))                                                       
        ORDER BY    department_name;


    2- QUERY ALTERADA COM CLÁUSULA WITH:

WITH
          DEPT_COSTS AS (
                          SELECT          D.DEPARTMENT_NAME,
                                                  SUM(E.SALARY) AS DEPT_TOTAL
                          FROM             HR.EMPLOYEES E
                          INNER JOIN  HR.DEPARTMENTS D
                              ON              E.DEPARTMENT_ID = D.DEPARTMENT_ID
                          GROUP BY    D.DEPARTMENT_NAME),
          AVG_COST AS (
                          SELECT         SUM(DEPT_TOTAL)/COUNT(*) AS DEPT_AVG
                          FROM            HR.DEPT_COSTS)
        SELECT         *
        FROM           DEPT_COSTS
        WHERE         DEPT_TOTAL >  ( SELECT  DEPT_AVG
                                                          FROM    AVG_COST)
        ORDER BY   department_name;


     Observem que na query 2, blocos de SQL redundantes foram eliminados através da criação da tabela temporária DEPT_COSTS. Em testes que eu fiz, o custo médio de execução dessa query caiu aproximadamente 30%, após utilizar a cláusula WITH (query 2).
   
 

LINKS ÚTEIS

Total de visualizações de página

Seguidores

Meu One Drive (antigo Sky Drive)