Neste artigo, vamos simular o processamento no banco de dados, aumentando gradativamente o seu workload, e ver o seu reflexo na Time Model. Criaremos uma tabela para salvar os snapshots sobre DB Time, DB CPU, e o total de waits, com objetivo de analisar os dados posteriormente para comparação. Obviamente, na vida real, isso não é necessário, pois temos um recurso que executa isso de forma muito mais completa e automática, que abordaremos em outros artigos (AWR).
Gerando script que criará a tabela que abrigará os dados históricos:
cat > create_tm_history.sql <<EOL
-- create table to save DBTIME, DB CPU, and total waits in it
DROP TABLE TM_HISTORY;
DROP SEQUENCE S;
CREATE SEQUENCE S;
CREATE TABLE TM_HISTORY AS SELECT S.NEXTVAL AS SNAP_ID,
DBTIME.VALUE/1000000 DBTIME,
DBCPU.VALUE/1000000 DBCPU,
(DBTIME.VALUE-DBCPU.VALUE)/1000000 WAIT_TIME,
(SELECT COUNT(*) FROM V\$SESSION WHERE USERNAME IS NOT NULL) USERS_CNT
FROM V\$SYS_TIME_MODEL DBTIME, V\$SYS_TIME_MODEL DBCPU
WHERE DBTIME.STAT_NAME = 'DB time' AND DBCPU.STAT_NAME = 'DB CPU';
EOL
Execução:
[oracle@oel7 scripts]$ pwd
/oracle/scripts
[oracle@oel7 scripts]$ cat > create_tm_history.sql <<EOL
>
WHERE DBTIME.STAT_NAME = 'DB time' AND DBCPU.STAT_NAME = 'DB CPU';
EOL> -- create table to save DBTIME, DB CPU, and total waits in it
> DROP TABLE TM_HISTORY;
> DROP SEQUENCE S;
> CREATE SEQUENCE S;
> CREATE TABLE TM_HISTORY AS SELECT S.NEXTVAL AS SNAP_ID,
> DBTIME.VALUE/1000000 DBTIME,
> DBCPU.VALUE/1000000 DBCPU,
> (DBTIME.VALUE-DBCPU.VALUE)/1000000 WAIT_TIME,
> (SELECT COUNT(*) FROM V\$SESSION WHERE USERNAME IS NOT NULL) USERS_CNT
> FROM V\$SYS_TIME_MODEL DBTIME, V\$SYS_TIME_MODEL DBCPU
> WHERE DBTIME.STAT_NAME = 'DB time' AND DBCPU.STAT_NAME = 'DB CPU';
> EOL
[oracle@oel7 scripts]$
Script para retornar os dados da tabela criada:
cat > display_tm_history.sql << EOL
-- retrieve data from TM_HISTORY
set linesize 180
SELECT
TO_CHAR(DBTIME,'999,999,999') DBTIME,
TO_CHAR(DBCPU,'999,999,999') DBCPU,
ROUND(DBCPU - LAG(DBCPU, 1, 0) OVER (ORDER BY DBCPU)) AS DBCPU_DIFF,
TO_CHAR(WAIT_TIME,'999,999,999,999') WAIT_TIME,
ROUND(WAIT_TIME - LAG(WAIT_TIME, 1, 0) OVER (ORDER BY WAIT_TIME)) AS WAIT_TIME_DIFF,
TO_CHAR((DBTIME-DBCPU)/DBTIME*100,'99.99') || '%' WAIT_PCT, USERS_CNT,
ROUND((DBTIME-DBCPU)/USERS_CNT) WAIT_USER_SHARE
FROM TM_HISTORY
ORDER BY SNAP_ID;
EOL
Log:
[oracle@oel7 scripts]$ cat > display_tm_history.sql << EOL
>
> -- retrieve data from TM_HISTORY
>
> set linesize 180
> SELECT
> TO_CHAR(DBTIME,'999,999,999') DBTIME,
> TO_CHAR(DBCPU,'999,999,999') DBCPU,
> ROUND(DBCPU - LAG(DBCPU, 1, 0) OVER (ORDER BY DBCPU)) AS DBCPU_DIFF,
> TO_CHAR(WAIT_TIME,'999,999,999,999') WAIT_TIME,
> ROUND(WAIT_TIME - LAG(WAIT_TIME, 1, 0) OVER (ORDER BY WAIT_TIME)) AS WAIT_TIME_DIFF,
> TO_CHAR((DBTIME-DBCPU)/DBTIME*100,'99.99') || '%' WAIT_PCT, USERS_CNT,
> ROUND((DBTIME-DBCPU)/USERS_CNT) WAIT_USER_SHARE
> FROM TM_HISTORY
> ORDER BY SNAP_ID;
> EOL
[oracle@oel7 scripts]$
Script para gerar os snapshots:
cat > take_tm_snapshot.sql <<EOL
-- save the current time model basic statistics into the TM_HISTORY table
INSERT INTO TM_HISTORY
SELECT
S.NEXTVAL AS SNAP_ID,
DBTIME.VALUE/1000000 DBTIME,
DBCPU.VALUE/1000000 DBCPU,
(DBTIME.VALUE-DBCPU.VALUE)/1000000 WAIT_TIME,
(SELECT COUNT(*) FROM V\$SESSION WHERE USERNAME IS NOT NULL) USERS_CNT
FROM V\$SYS_TIME_MODEL DBTIME, V\$SYS_TIME_MODEL DBCPU
WHERE DBTIME.STAT_NAME = 'DB time' AND DBCPU.STAT_NAME = 'DB CPU';
COMMIT;
EOL
Log:
[oracle@oel7 scripts]$ cat > take_tm_snapshot.sql <<EOL
>
> -- save the current time model basic statistics into the TM_HISTORY table
> INSERT INTO TM_HISTORY
> SELECT
> S.NEXTVAL AS SNAP_ID,
> DBTIME.VALUE/1000000 DBTIME,
> DBCPU.VALUE/1000000 DBCPU,
> (DBTIME.VALUE-DBCPU.VALUE)/1000000 WAIT_TIME,
> (SELECT COUNT(*) FROM V\$SESSION WHERE USERNAME IS NOT NULL) USERS_CNT
> FROM V\$SYS_TIME_MODEL DBTIME, V\$SYS_TIME_MODEL DBCPU
> WHERE DBTIME.STAT_NAME = 'DB time' AND DBCPU.STAT_NAME = 'DB CPU';
> COMMIT;
> EOL
[oracle@oel7 scripts]$
Criando nossa estrutura:
SQL> @create_tm_history.sql
Table dropped.
Sequence dropped.
Sequence created.
Table created.
Visualizando os dados da tabela:
SQL> @display_tm_history.sql
DBTIME DBCPU DBCPU_DIFF WAIT_TIME WAIT_TIME_DIFF WAIT_PC USERS_CNT WAIT_USER_SHARE
------------ ------------ ---------- ---------------- -------------- ------- ---------- ---------------
38 2 2 35 35 93.44% 3 12
Abrindo o SwingBench, e configurando uma carga simulando 10 usuários simultâneos:
Assim que vejo que os processos estão sendo realizados no banco, executo o script para tirar o snapshot:
[oracle@oel7 scripts]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Mon Sep 13 20:37:16 2021
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL> @take_tm_snapshot.sql
1 row created.
Commit complete.
Parando o processamento:
Analisando o conteúdo de nossa tabela. O números de usuários aumentaram, e a porcetagem de Waits (que já eram altas, mas que podemos desconsiderar pois eu havia acabado de levantar o banco) também:
SQL> @display_tm_history.sql
DBTIME DBCPU DBCPU_DIFF WAIT_TIME WAIT_TIME_DIFF WAIT_PC USERS_CNT WAIT_USER_SHARE
------------ ------------ ---------- ---------------- -------------- ------- ---------- ---------------
38 2 2 35 35 93.44% 3 12
601 19 17 581 546 96.77% 13 45
Agora vou fazer a mesma dinâmica, mas aumentando o número de usuário para 30, e depois para 60, retirando um snapshot de cada momento:
SQL> @take_tm_snapshot.sql
1 row created.
Commit complete.
SQL> @take_tm_snapshot.sql
1 row created.
Commit complete.
Com o material, podemos analisar o ambiente, até em relação à sua escalabilidade. Em ambientes reais, o ideal é nos atentarmos na porcentagem de waits gerados, pois podem ser um indicativo de lentidão. Quanto maior o número de usuários clientes, maior será a CPU Time e DB Time. Porém, caso este número aumente, e a proporção de CPU e DB Time não é a mesma a mesma, temos um problema de escalabilidade, onde os DB Waits aumentam mais que o DB CPU.
SQL> @display_tm_history.sql
DBTIME DBCPU DBCPU_DIFF WAIT_TIME WAIT_TIME_DIFF WAIT_PC USERS_CNT WAIT_USER_SHARE
------------ ------------ ---------- ---------------- -------------- ------- ---------- ---------------
38 2 2 35 35 93.44% 3 12
601 19 17 581 546 96.77% 13 45
991 68 49 923 342 93.13% 33 28
1,517 219 151 1,299 375 85.58% 63 21
Obs: Este procedimento foi criado pelo senhor Ahmed Baraka (www.ahmedbaraka.com) e foi apenas reproduzido por mim em um laboratório pessoal para fins de aprendizado.