Olá pessoal!

Espero que estejam bem!

Garantir a alta disponibilidade dos nossos bancos de dados Oracle é crucial para manter o desempenho ideal e cumprir os Acordos de Nível de Serviço (SLAs). O Oracle Enterprise Manager (OEM) oferece uma maneira bastante completa de monitorar e gerenciar o uptime dos banco de dados monitorados. Dito isso, recebi uma ligação de um cliente que perguntou:

  • Existe alguma maneira de calcular o tempo de atividade do banco de dados nos últimos 30 dias usando uma abordagem simples e rápida?

Bem, a resposta é: sim!

O OEM tem as informações sobre uptime/disponibilidade na sua interface gráfica, onde você pode navegar até os alvos e verificar. Não sou um grande especialista em OEM, mas eu diria que talvez você possa criar algum relatório (ou talvez já exista) sobre disponibilidade.

OK, mas nós somos DBAs, gostamos de trabalhar usando SSH e SQL*Plus, não é? Então, a questão é:

  • Existe alguma maneira de calcular o tempo de uptime do banco de dados nos últimos 30 dias usando instruções SQL?

Novamente, a resposta é: sim! Com certeza!

Se você estiver usando o Oracle Enterprise Manager, pode executar uma instrução SELECT diretamente nas views do OEM para calcular manualmente o uptime dos bancos de dados.

Esse blog post irá ajudá-lo a calcular o tempo de uptime do banco de dados e a porcentagem de SLA usando consulta SQL nas views do OEM.

Abaixo, vamos fazer um drill drown pela consulta SQL usada para calcular o uptime dos bancos de dados, tanto para bancos de dados single instance, quanto para bancos de dados RAC (Real Application Clusters) nos últimos 30 dias.

Below, we’ll walkthrough the SQL query used to calculate database uptime for both individual databases and RAC (Real Application Clusters) databases over the last 30 days.

Você precisa se conectar ao BD que é o repositório do OEM.

A consulta completa é essa:

COLUMN target_name FORMAT a11
COLUMN uptime_hours FORMAT 9999
SET LINESIZE 200
SET PAGESIZE 500

WITH availability AS (
  SELECT 
    target_name,
    target_type,
    CASE
      WHEN INSTR(target_name, '_') > 0 THEN SUBSTR(target_name, 1, INSTR(target_name, '_') - 1)
      ELSE target_name
    END AS cluster_name,
    availability_status,
    start_timestamp,
    NVL(end_timestamp, SYSTIMESTAMP) AS end_timestamp
  FROM 
    SYSMAN.MGMT$AVAILABILITY_HISTORY
  WHERE 
    target_type = 'oracle_database'
    AND start_timestamp >= TRUNC(SYSDATE) - 30
),
downtime AS (
  SELECT 
    cluster_name,
    SUM(CASE WHEN availability_status != 'Target Up' THEN (end_timestamp - start_timestamp) * 24 ELSE 0 END) AS downtime_hours
  FROM 
    availability
  GROUP BY 
    cluster_name
),
adjusted_uptime AS (
  SELECT 
    cluster_name,
    ROUND(720 - SUM(downtime_hours), 0) AS uptime_hours
  FROM 
    downtime
  GROUP BY 
    cluster_name
)
SELECT 
  cluster_name AS target_name,
  uptime_hours,
  ROUND((uptime_hours / 720) * 100, 2) AS sla_percentage
FROM 
  adjusted_uptime
ORDER BY 
  cluster_name;

Vamos fazer o breakdown da query. A query consiste em três partes:

  1. Extraindo e Normalizando Intervalos
  2. Calculando o Downtime
  3. Calculando o Uptime e o Percentual de SLA

Vamos começar com:

  1. Extraindo e Normalizando Intervalos

Essa parte da query extrai dados relevantes da view MGMT$AVAILABILITY_HISTORY e normaliza o nome do cluster para BD’s RAC:

WITH availability AS (
  SELECT 
    target_name,
    target_type,
    CASE
      WHEN INSTR(target_name, '_') > 0 THEN SUBSTR(target_name, 1, INSTR(target_name, '_') - 1)
      ELSE target_name
    END AS cluster_name,
    availability_status,
    start_timestamp,
    NVL(end_timestamp, SYSTIMESTAMP) AS end_timestamp
  FROM 
    SYSMAN.MGMT$AVAILABILITY_HISTORY
  WHERE 
    target_type = 'oracle_database'
    AND start_timestamp >= TRUNC(SYSDATE) - 30
)

Explicação::

  • target_name: O nome do banco de dados ou instância;
  • target_type: O tipo do alvo, que é ‘oracle_database’;
  • cluster_name: Nome normalizado para clusters RAC, extraindo a parte do target_name antes do primeiro underscore. Para bancos de dados single instance, usa-se o próprio target_name;
  • availability_status: O status do banco de dados (por exemplo, ‘Target Up’, ‘Target Down’);
  • start_timestamp: A hora de início do intervalo de status;
  • end_timestamp: A hora de término do intervalo de status, padronizando para o timestamp atual se estiver nulo.

Vamos agora para:

2. Calculando Downtime:

Essa parte agrega as horas de downtime para cada cluster:

downtime AS (
  SELECT 
    cluster_name,
    SUM(CASE WHEN availability_status != 'Target Up' THEN (end_timestamp - start_timestamp) * 24 ELSE 0 END) AS downtime_hours
  FROM 
    availability
  GROUP BY 
    cluster_name
)

Explicação:

  • downtime_hours: Total de horas que o banco de dados esteve down (Eu estou assumindo que o BD esteve down se availability_status for diferente de ‘Target Up’).

Essa parte da query vai também vai somar as horas de downtime para cada cluster.

Vamos agora para:

3. Calculando o Uptime e o Percentual de SLA:

Essa parte calcula o uptime ajustado e o percentual de SLA com base no total de horas possíveis em um mês, 30 dias (720 horas):

adjusted_uptime AS (
  SELECT 
    cluster_name,
    ROUND(720 - SUM(downtime_hours), 0) AS uptime_hours
  FROM 
    downtime
  GROUP BY 
    cluster_name
)
SELECT 
  cluster_name AS target_name,
  uptime_hours,
  ROUND((uptime_hours / 720) * 100, 2) AS sla_percentage
FROM 
  adjusted_uptime
ORDER BY 
  cluster_name;

Explicação::

  • uptime_hours: Total possível de horas (720) subtraído pelas horas de downtime;
  • sla_percentage: O percentual de SLA calculado como (uptime_hours / 720) * 100.

Seguindo esta abordagem, você pode calcular com precisão o uptime dos bancos de dados e o percentual de SLA para seus bancos de dados Oracle usando views do OEM. Este método é particularmente útil para gerar relatórios de uptime e garantir que seus bancos de dados atendam aos padrões de disponibilidade necessários.

Abaixo temos um exemplo de saída. Os nomes dos bancos de dados foram substituídos por razões de segurança:

TARGET_NAME UPTIME_HOURS SLA_PERCENTAGE
----------- ------------ --------------
DB01		    701 	 97.36
DB02		    681 	 94.58
DB03		    708 	 98.33
DB04		    711 	 98.75
DB05		    705 	 97.92
DB06		    692 	 96.11
DB07		    711 	 98.75
DB08		    701 	 97.36
DB09		    705 	 97.92
DB10		    703 	 97.64
DB11		    689 	 95.69
DB12		    701 	 97.36
DB13		    713 	 99.03
DB14		    714 	 99.17
DB15		    714 	 99.17
DB16		    714 	 99.17
DB17		    714 	 99.17
DB18		    714 	 99.17
DB19		    714 	 99.17
DB20		    714 	 99.17
DB21		    708 	 98.33
DB22		    547 	 75.97

Espero que seja útil!

Um abraço,

Vinicius