Script Bash para Monitorar o Consumo de CPU por PDBs e CDB$ROOT no Oracle Standard Edition


Ao administrar bancos Oracle em arquitetura Multitenant, um desafio comum é entender como o consumo de CPU está distribuído entre o CDB$ROOT e os PDBs (Pluggable Databases). Pensando nisso, desenvolvi um script simples em Bash que coleta esses dados diretamente da v$sys_time_model e exibe a porcentagem de uso para cada PDB.

Este script é bastante útil para consolidar as informações de CPU de ambientes Standard Edition com mais de um PDB, uma vez que nesta versão não existe uma visão consolidada, sendo necessário consultar manualmente em cada um dos PDBs (não que isso seja um problema). Porém com o script nos da mais possibilidades, como por exemplo agendar e armazenar dados das coleta em uma tabela, por exemplo.

 Objetivo

  • Coletar o tempo total de CPU utilizado no CDB$ROOT (base de referência);

  • Coletar o tempo de CPU utilizado por cada PDB aberto em modo READ WRITE;

  • Calcular e exibir o percentual de uso de cada PDB em relação ao total da instância.

Utiliza-se a métrica DB CPU da visão v$sys_time_model, convertida de microssegundos para segundos, para avaliar o uso de CPU. A métrica é coletada para o CDB$ROOT e para cada PDB individualmente, com o cálculo percentual feito via awk.

O Script 

Gere um script .sh com os comandos abaixo e posteriormente execute-o.
#!/bin/bash

export PATH=$ORACLE_HOME/bin:$PATH

PDB_LIST=$(mktemp)
declare -A CPU_VALUES

# Coleta CPU do CDB$ROOT
ROOT_CPU=$(sqlplus -s "/ as sysdba" <<EOF
ALTER SESSION SET CONTAINER = CDB\$ROOT;
SELECT ROUND(value / 1000000, 2) FROM v\$sys_time_model WHERE stat_name = 'DB CPU';
EXIT;
EOF
)
ROOT_CPU=$(echo "$ROOT_CPU" | tr -d '\n\r[:space:]')
[ -z "$ROOT_CPU" ] && ROOT_CPU=0

# Cabeçalho
echo "PDB_NAME           | CPU_SECONDS | % USO"
echo "-------------------|-------------|--------"
printf "%-19s| %-12s| %6s%%\n" "CDB\$ROOT" "$ROOT_CPU" "100.00"

# Lista de PDBs abertos
sqlplus -s "/ as sysdba" <<EOF > /dev/null
SPOOL $PDB_LIST
SELECT TRIM(name) FROM v\$containers WHERE con_id > 2 AND open_mode = 'READ WRITE';
SPOOL OFF
EXIT;
EOF

# Coleta CPU por PDB
while IFS= read -r PDB; do
  PDB=$(echo "$PDB" | xargs)
  [ -z "$PDB" ] && continue

  CPU=$(sqlplus -s "/ as sysdba" <<EOF
ALTER SESSION SET CONTAINER = "$PDB";
SELECT ROUND(value / 1000000, 2) FROM v\$sys_time_model WHERE stat_name = 'DB CPU';
EXIT;
EOF
)
  CPU=$(echo "$CPU" | tr -d '\n\r[:space:]')
  [[ -z "$CPU" || "$CPU" == *ORA-* ]] && CPU=0
  CPU_VALUES["$PDB"]="$CPU"
done < "$PDB_LIST"

# Apresentação final
for PDB in "${!CPU_VALUES[@]}"; do
  CPU_VAL=${CPU_VALUES[$PDB]}
  PCT=$(awk -v used="$CPU_VAL" -v total="$ROOT_CPU" 'BEGIN { if (total > 0) printf "%.2f", (used/total)*100; else print "0.00" }')
  printf "%-19s| %-12s| %6s%%\n" "$PDB" "$CPU_VAL" "$PCT"
done

rm -f "$PDB_LIST"

Execução:

[oracle@dbsystem23ai tmp]$
[oracle@dbsystem23ai tmp]$ sh coletar_cpu_pdbs.sh
PDB_NAME           | CPU_SECONDS | % USO
-------------------|-------------|--------
CDB$ROOT           | 36383.27    | 100.00%
LAMIMDB_PDB2       | 4.38        |   0.01%
LAMIMDB_PDB1       | 11785.75    |  32.39%
[oracle@dbsystem23ai tmp]$

Observações:

  • A métrica utilizada (DB CPU) pode não refletir 100% do consumo real da máquina (existem outras como background cpu time).
  • O script ignora PDBs em MOUNTED ou READ ONLY.
  • É necessário executar como SYSDBA.
  • Pode ser agendado via cron para coleta periódica.

Comentários