20 de mar. de 2013


Olá pessoal,

Hoje vou falar sobre consultas hierárquicas no banco de dados Oracle. Esse tipo de estrutura é muito útil para várias situações desde criação de itens de um menu até uma simulação de informação.

Bom...

Uma consulta hierárquica relaciona registros com base em uma relação de parentesco. Para que seja possível realizar uma consulta de forma hierárquica de um conjunto de dados, é necessário que exista uma relação de lógica entre os registros (pai e filho).

Vou dar um exemplo mais prático: criação de itens de menu. Digamos que queiramos criar um menu da seguinte forma:

1.Item 1
--1.1.Item 1, parte 1
--1.2.Item 1, parte 2
----1.2.1.Item 1, parte 2, seção 1
----1.2.2.Item 1, parte 2, seção 2
2.Item 2
--2.1.Item 2, parte 1
--2.2.Item 2, parte 2

Vou criar uma tabela chamada MENU para ajudar no entendimento:

CREATE TABLE menu
(
   cod      NUMBER (4),
   codpai   NUMBER (4),
   campo    VARCHAR (30),
   CONSTRAINT PK_MENU PRIMARY KEY (COD),
   CONSTRAINT FK_MENU_CODPAI FOREIGN KEY (CODPAI) REFERENCES DIARIO.MENU (COD)
);

Agora vou popular a tabela com registros de mesmo valor do citado no exemplo literal acima:

INSERT INTO MENU VALUES (1, NULL, 'Item 1');
INSERT INTO MENU VALUES (2,1,'Item 1,parte 1');
INSERT INTO MENU VALUES (3,1,'Item 1,parte 2');
INSERT INTO MENU VALUES (4,3,'Item 1,parte 2, seção 1');
INSERT INTO MENU VALUES (5,3,'Item 1,parte 2, seção 2');
INSERT INTO MENU VALUES (6,NULL,'Item 2');
INSERT INTO MENU VALUES (7,6,'Item 2,parte 1');
INSERT INTO MENU VALUES (8,6,'Item 2,parte 2');
COMMIT;

Verificando de forma normal os registros executando a consulta abaixo temos o resultado da Figura 2:

SELECT cod, codpai, campo FROM MENU ORDER BY 1 ASC, 2 ASC;

 Figura 1 - Resultado da consulta do exemplo 1. (Fonte: autoria própria)

Agora vamos ver como realizar uma consulta hierárquica contra essa tabela. Para isso, vamos entender um pouco do conceito.

A estrutura utilizada para realizar consultas dessa natureza é: START WITH ... CONNECT BY, e sua sintaxe pode ser vista na Figura 2.
Figura 2 - Sintaxe para consultas hierárquicas. (Fonte: Oracle Corporation)

O comando START WITH:
Determina quais são os registros “raiz” que devem ser utilizados para iniciar a consulta. No nosso caso, serão os registros com “codpai” nulo.

O comando CONNECT BY PRIOR:
Este comando especifica a relação entre registros pai e filho. No nosso caso, “cod” deverá ter um correspondente em “codpai”. É importante ressaltar que se a igualdade for invertida, ou seja, “codpai” foi igual a “cod” o resultado será totalmente diferente, pois o Oracle considera o argumento da esquerda como pai (ou raiz) e o da direita da igualdade como filho.

A consulta hierárquica para atender a solução é a seguinte:

SELECT cod,
           codpai,
           LEVEL,
           LPAD (' ',(LEVEL - 1) * 3, '-') || campo AS "Descrição"
      FROM menu
START WITH codpai IS NULL
CONNECT BY PRIOR cod = codpai
ORDER BY cod ASC, codpai ASC, campo ASC;

A pseudo-coluna LEVEL sempre está disponível para consultas hierárquicas e serve para indicar o nível em que o registro se encontra em relação à raiz.

O resultado da consulta acima pode ser conferido na Figura 3.

Figura 3 - Resultado da consulta do exemplo 1. (Fonte: autoria própria)

Consultas hierárquicas podem ter muitas utilidades, e os comandos connect by e start with podem nos ajudar de várias outras formas.

Por exemplo, uma simulação de valores de 1 a 10:

SELECT LEVEL "Número" FROM DUAL CONNECT BY LEVEL <= 10 ORDER BY 1 ASC;

O resultado da consulta acima pode ser conferido na Figura 4.
Figura 4 - Simulação de contagem de 1 a 10. (Fonte: autoria própria)

Recentemente passei por uma situação e usei connect by e start with para resolver. A situação foi a seguinte, precisava saber qual o primeiro domingo do mês corrente.

Alguém se habilita com uma solução?

Bom...

A que usei foi a seguinte: simulei dados para os 7 primeiros dias do mês (e com certeza o primeiro domingo estará entre eles), e numa consulta mais externa verifiquei qual das datas correspondia ao primeiro dia da semana, no caso o domingo. A consulta foi a seguinte:

SELECT dia
  FROM (SELECT TRUNC (SYSDATE, 'MM') + b.simulado dia FROM DUAL a,
                ( SELECT LEVEL - 1 simulado FROM DUAL CONNECT BY LEVEL <= 7) b
             )
 WHERE TO_CHAR (dia, 'D') = '1';

O resultado para a consulta pode ser conferida na Figura 5.
Figura 5 – Consulta para saber o primeiro domingo do mês corrente. (Fonte: autoria própria)

Essa foi uma forma simples e prática para a solução do meu problema.

Por hoje é isso, pessoal!

Espero ter conseguido passar o entendimento de forma clara e objetiva.

Até a próxima!

Referências:
Oracle Corporation – Hierarchical Queries. Disponível em: http://docs.oracle.com/cd/B28359_01/server.111/b28286/queries003.htm. Acessado: 18/03/2013.

Lusa, Diego Antonio - Uso do CONNECT BY no Oracle. Disponível em: http://www.devmedia.com.br/uso-do-connect-by-no-oracle/23647. Acessado:18/03/2013.

Raphael Fernandes, quarta-feira, março 20, 2013

4 comentários

18 de mar. de 2013


Olá pessoal!

Hoje quero falar um pouco sobre as estatísticas no banco de dados Oracle e a importância delas para o bom desempenho dos scripts submetidos ao banco.

Inicialmente, vou abordar os métodos existentes para realizar a coleta das estatísticas, com algumas características e tentar estabelecer uma comparação entre eles.

Lembrando que em um post anterior, comentei sobre como verificar se as estatísticas de sua instância Oracle foram atualizadas recentemente.

Vou fazer uma explicação rápida sobre plano de execução (isso porque pretendo fazer um post sobre o assunto em outro momento).  O Plano de Execução de uma instrução SQL é uma seqüência de operações que o Banco de Dados Oracle realiza para executar uma instrução. O plano de uma instrução pode se alterar conforme o ambiente em que está sendo executado: versão do Oracle, hardware, parâmetros de servidor (sistema ou sessão), volume de dados e estatísticas.  Esse último item é o ponto que quero focar no artigo de hoje.

Estatística é uma coleção de dados detalhados sobre o banco de dados e seus objetos. As estatísticas são usadas pelo otimizador de consultas do Oracle para escolher o melhor plano de execução a ser executado.

Abaixo, seguindo a definição da Oracle, seguem itens inclusos nas estatísticas:
- Para o caso de tabela:
                - Número de linhas (registros)
                - Número de blocos de dados
                - Comprimento médio das linhas
- Para as colunas:
                - Número de valores distintos na coluna (NDV – Number of Distinct Values)
                - Número de colunas nulas
                - Distribuição dos dados (histogramas)
- Estatísticas dos índices:
                - Número de blocos folha
                - Níveis
- Fator de agrupamento
- Estatísticas de sistema:
                - Desempenho e utilização de I/O
                - Desempenho e utilização de CPU

Entendendo quais informações são levadas em consideração nas estatísticas, torna de mais fácil entendimento a razão que elas auxiliam na escolha do otimizador do Oracle de “traçar” um plano de execução mais eficiente para acessar um dado (ou um conjunto de dados) da base.

Existem algumas maneiras de se atualizar as estatísticas, inclusive o próprio banco de dados Oracle já realiza diante de algumas circunstâncias, tais como modificação significativa na tabela (mais de 10% dos registros caso o objeto esteja habilitado para monitoramento). As formas de atualização das estatísticas são as seguintes:

Atualização através do comando ANALYZE:
A sintaxe para coletar estatísticas de uma tabela é a seguinte:
ANALYZE TABLE OWNER.TABELA COMPUTE STATISTICS;

Algumas características sobre essa estrutura de atualização das estatísticas, segundo Fábio Prado:
a.       Coleta ou exclui estatísticas sobre índices, tabelas ou clusters; de forma exata ou estimada em um número ou percentual de registros;
b.      Pode não precisar a informação de cardinalidade da tabela no que diz respeito a valores distintos nas colunas (NDV);
c.       Foi bastante eficiente nas versões anteriores do banco de dados Oracle, mas nas versões atuais existem apenas para manter a compatibilidade.

      Atualização através do pacote DBMS_UTILITY:
A sintaxe para coletar estatísticas de um esquema é a seguinte:
EXEC DBMS_UTILITY.ANALYZE_SCHEMA (OWNER,'ESTIMATE',99,20,'FOR TABLE');

ou pode-se atualizar as estatísticas de toda a instância através do commando:
EXEC DBMS_UTILITY.ANALYZE_DATABASE ('ESTIMATE',100,20,'FOR TABLE');

É importante lembrar que diferente do comando ANALYZE, o pacote DBMS_UTILITY pode coletar as estatísticas de um esquema ou de todo um banco de dados.

      Atualização através do pacote DBMS_STATS:
A sintaxe para coletar estatísticas de uma tabela é a seguinte:
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>'OWNER', TABNAME=>'TABELA', ESTIMATE_PERCENT=>20);

A sintaxe para coletar estatísticas de um esquema é a seguinte:
EXEC DBMS_STATS.GATHER_SCHEMA_STATS('OWNER',ESTIMATE_PERCENT=> 20);

A sintaxe para coletar estatísticas de toda a instância é a seguinte:
EXEC DBMS_STATS.GATHER_DATABASE_STATS;

Para coletar estatísticas de sistema (dicionário de dados):
EXEC DBMS_STATS.GATHER_DICTIONARY_STATS;

Algumas características sobre essa estrutura de atualização das estatísticas, também segundo Fábio Prado:

a.       Foi introduzido no Oracle 8i e hoje é o método mais eficiente para coletar estatísticas para o CBO. É o método de coleta de estatísticas atualmente recomendado pela Oracle;
b.      Permite coletar estatísticas exatas ou estimadas de objetos individualmente (tabelas, índices, cluster etc), esquemas, banco de dados completo e de sistema;
c.       Permite execução paralela, transferência de estatísticas entre servidores e é mais preciso que os métodos anteriores pois gera histogramas, que são extremamente úteis para otimizar scripts SQL que acessam colunas com valores dispersos.

É importante saber que utilizar o pacote DBMS_STATS é a forma mais completa e justamente por esse motivo pode ser o método mais lento de coleta de estatística entre os apresentados. Para garantir um desempenho otimizado do seu banco, é de fundamental importância que as estatísticas dele estejam atualizadas. Lembro novamente que o Oracle realiza de forma automática a coleta das estatísticas diante de algumas situações (isso nas versões “mais recentes” do banco Oracle – a partir do 10g): diariamente caso as estatísticas estejam desatualizadas ou quando existir muita movimentação dos registros – cerca de 10% do total (configurável) – do objeto (que também significa que as estatísticas estão desatualizadas).

Bom pessoal. Por hoje é isso!
Espero ter conseguido passar o básico sobre coleta de estatísticas no BD Oracle.
Até a próxima!


Referências:

ORACLE CORPORATION - MANAGING OPTIMIZER STATISTICS. Disponível em:  http://docs.oracle.com/cd/B13789_01/server.101/b10752/stats.htm. Acessado em: 02/03/2013.

ORACLE CORPORATION - DBMS_STATS. Disponível em:  http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_stats.htm. Acessado em: 02/03/2013.

PRADO, FÁBIO. Disponível em: http://www.fabioprado.net/2012/04/coletando-estatisticas-para-o.html. Acessado em: 17/03/2013.

DBPEDIAS. Disponível: http://dbpedias.com/wiki/Oracle:DBMS_UTILITY.ANALYZE_DATABASE. Acessado em: 02/03/2013.

DBPEDIAS. Disponível em: http://dbpedias.com/wiki/Oracle:DBMS_UTILITY.ANALYZE_SCHEMA. Acessado em: 02/03/2013.

Raphael Fernandes, segunda-feira, março 18, 2013

1 comentário

15 de mar. de 2013


Muito bom dia, a todos!

Hoje vou falar sobre como verificar se as estatísticas das tabelas e índices da sua instância estão atualizadas. Quero lembrar que o otimizador do banco de dados Oracle nas versões “mais recentes”, otimizador baseado em custo (CBO - Cost-Based Optimizer), que  é o grande responsável por traçar o plano de execução, (definindo a “melhor” forma de se acessar um dado optando pelo “mais eficiente” método de acesso), utiliza as estatísticas para fazê-lo. Dessa forma, pode-se afirmar que a coleta e atualização das estatísticas está diretamente ligada à performance do banco de dados.

Bom...

Criei duas consultas para verificarmos quando foi a última vez que o objeto (índice ou tabela) teve suas estatísticas coletadas. É importante saber que o banco Oracle realiza de forma automática a coleta das estatísticas para o caso de uma variação muito grande do tamanho do objeto (cerca de 10%), mas isso é um assunto que falarei em outra oportunidade.

Na projeção da primeira consulta, deve-se observar a data de atualização das estatísticas das tabelas do seu ambiente:

SELECT STAT.OWNER AS "Schema proprietário",
         STAT.TABLE_NAME AS "Nome do objeto",
         STAT.OBJECT_TYPE AS "Tipo do objeto",
         STAT.NUM_ROWS AS "Quant. de Linhas",
         STAT.LAST_ANALYZED AS "Última coleta das estatísticas"
    FROM SYS.DBA_TAB_STATISTICS STAT
   WHERE STAT.OWNER NOT IN ('SYS', 'SYSTEM', 'SYSMAN', 'DBSNMP')
ORDER BY LAST_ANALYZED;

Já na projeção da segunda (abaixo), é possível saber quando as estatísticas dos índices foram coletadas pela última vez:

SELECT STAT.OWNER AS "Schema proprietário",
         STAT. TABLE_NAME AS "Nome do objeto",
         STAT.OBJECT_TYPE AS "Tipo do objeto",
         STAT.NUM_ROWS AS "Quant. de Linhas",
         STAT.LAST_ANALYZED AS "Última coleta das estatísticas"
    FROM SYS.DBA_IND_STATISTICS STAT
   WHERE STAT.OWNER NOT IN ('SYS', 'SYSTEM', 'SYSMAN', 'DBSNMP')
ORDER BY LAST_ANALYZED;

Os campos projetados em ambas as consultas são:
"Schema proprietário": - campo que informa o esquema dono do objeto;
"Nome do objeto": - campo que informa o nome do objeto;
"Tipo do objeto": - informa o tipo do campo, no caso: tabela ou índice;
"Quant. de Linhas": - exibe a quantidade de registros do objeto;
"Última coleta das estatísticas": - data e hora da realização da última coleta (mais recente) das estatísticas do objeto em questão.

Na seleção da informação, abstraí alguns esquemas, pois são os reservados e utilizados pelo sistema, e não cabem termos conhecimento das estatísticas desses usuários.

A ordenação da informação está em ordem ascendente de data, ou seja, da menor para a maior apenas para facilitar e sabermos que os objetos com as estatísticas mais desatualizadas aparecerão na frente dos dados.

Por hoje é só!

Até a próxima!

Raphael Fernandes, sexta-feira, março 15, 2013

Sem comentários