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

14 de mar. de 2013


Olá pessoal!

Existem algumas formas de se analisar os scripts submetidos ao banco de dados Oracle quanto a sua performance.  Uma dessas formas é através de uma view do esquema SYS chamada V_$SQLAREA, ou através do sinônimo público V$SQLAREA que está setado para a tabela.

Bom, de qualquer forma, nesse objeto existem informações interessantes para o acompanhamento dos scripts submetidos ao servidor de banco, mesmo que eles não tenham sido concluídos com sucesso.

A consulta é a seguinte:

SELECT *
  FROM (  SELECT ROUND ( ( (cpu_time / 1000000) / 60), 2) AS "Tempo total de CPU",
                 executions AS "Quant. exec.",
                 rows_processed AS "Quant. linhas proc.",
                 disk_reads AS "Leituras no disco",
                 first_load_time AS "Primeira utilização",
                 last_load_time AS "Última utilização",
                 parsing_schema_name AS "Usuário analisado",
                 sql_text AS "SQL exec."
            FROM v$sqlarea
           WHERE parsing_schema_name NOT IN ('SYS', 'SYSTEM', 'SYSMAN', 'DBSNMP')
        ORDER BY 1 DESC)
 WHERE ROWNUM <= 10;

Nesse caso, a seleção da consulta mais externa (cláusula where) faz com que o retorno sejam de apenas os 10 scripts com maior tempo total de CPU (garantido no sort da consulta interna), mas podemos alterar esse valor ou retirar a condição. Na seleção da consulta mais interna, retirei os usuários de controle do DBA e do próprio SGBD Oracle, para que a análise possa ser feita apenas por aplicações e pessoas.

Vou explicar rapidamente as informações da projeção (cláusula select):

"Tempo total de CPU" – nesse “campo” é retornado o tempo total de CPU gasto para executar todas as vezes o script em questão. Fiz uma continha para exibir o tempo em minutos;

"Quant. exec" – nesse “campo” é retornado a quantidade de vezes que o SQL em questão foi executado desde sua primeira vez que foi submetido;

"Quant. linhas proc." – nesse “campo” é exibido a quantidade total de linhas processadas em todas as execuções da SQL em questão;

"Leituras no disco" – nesse “campo” é retornado a quantidade total de leituras realizadas no disco;

"Primeira utilização" – informa a data e hora da primeira utilização da SQL em questão, ou pelo menos a mais recente das “primeiras vezes”;

"Última utilização" – informa a data e hora da última utilização da SQL em questão;

"Usuário analisado " – informa qual o usuário da instância Oracle que realizou a SQL;

"SQL exec." – informa o script SQL submetido.

Grande abraço e até a próxima!!

Raphael Fernandes, quinta-feira, março 14, 2013

6 comentários