Monitoramento básico de objetos no Oracle

Bom, todo DBA que se prese deve acompanhar o crescimento da base conforme o tempo. Prever o espaço em disco necessário nos próximos meses, saber qual época ocorre maior crescimento da base. Acompanhar de perto objetos críticos que ocupam mais espeço, etc. É claro que a própria Oracle e outros fornecedores possuem ferramentas bastente sofisticadas para fazer algumas destas coisas. É bem verdade que boa parte delas faz em maior ou menor grau algo bem semelhante ao que vou mostrar adiante. No entanto, eu gosto da minha solução, pois eu consigo entendê-la facilmente e modificar para necessidades específicas. No mínimo é um bom exercício de aprendizado.

Vejamos alguns requisitos que eu montei:

  • Ser compatível com pelo menos o Oracle 8 em diante;
  • Armazenar todas informações num tablespace separado, para que a coleta de dados não influencie nos demais tablespaces;
  • Utilizar um esquema separado para a criação de todos os objetos envolvidos. O usuário em questão deverá ser bloqueado e ter o mínimo de privilégios necessários;
  • Criar uma tabela para registrar a data de duração no disparo de cada script e outra para os erros que por ventura venham a ocorrer;
  • Coletar as seguintes informações com as respectivas periodicidades:
    • Dados sobre o tamanho dos tablespaces uma vez por mês;
    • Dados sobre a quantidade e tipo de objetos por esquema uma vez por dia, atualizando apenas as mudanças ocorridas;
    • Nome dos objetos inválidos auma vez por dia, atualizando apenas as mudanças ocorridas;
    • Tamanhode objetos que ocupem mais de 64MB ou tenham mais de 50 extents ou mais de um milhão de registros uma vez por semana, atualizando apenas as mudanças ocorridas;

Objetos

CREATE TABLESPACE 'DBA_LOG_DADOS'
  DATAFILE '/u01/oradata/nome_da_base/dba_log_dados_01.dbf'
  SIZE 100M LOGGING EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;
 
CREATE USER dba_log IDENTIFIED BY dba
    DEFAULT TABLESPACE dba_log_dados
    QUOTA UNLIMITED ON dba_log_dados
    ACCOUNT LOCK;
 
GRANT CREATE PROCEDURE TO dba_log;
GRANT CREATE TABLE TO dba_log;
 
-- Executar como SYSDBA
GRANT SELECT ON dba_objects TO dba_log;
GRANT SELECT ON dba_segments TO dba_log;
GRANT SELECT ON dba_data_files TO dba_log;
GRANT SELECT ON dba_free_space TO dba_log;
GRANT SELECT ON dba_tables TO dba_log;
 
CREATE SEQUENCE dba_log.log_seq;
 
CREATE TABLE dba_log.log(
    id_log      NUMBER(10),
    rotina      varchar2(100),
    usuario     varchar2(30) DEFAULT USER,
    inicio      DATE DEFAULT SYSDATE,
    fim         DATE,
    CONSTRAINT  log_pk PRIMARY KEY(id_log)
);
 
CREATE TABLE dba_log.erros (
    id_log      NUMBER(10),
    cod_erro    NUMBER(10),
    mensagem     varchar2(64),
    DATA        TIMESTAMP DEFAULT SYSTIMESTAMP
);
 
CREATE TABLE dba_log.tablespace (
    nome        varchar2(30),
    maximo      NUMBER(8) NOT NULL,
    alocado     NUMBER(8) NOT NULL,
    utilizado   NUMBER(8) NOT NULL,
    livre       NUMBER(8) NOT NULL,
    DATA        DATE DEFAULT SYSDATE,
    CONSTRAINT tablespaces_pk PRIMARY KEY (nome,DATA)
);
 
CREATE OR REPLACE PROCEDURE dba_log.tablespace_load AS
  v_log_seq NUMBER(10);
  v_code NUMBER(10);
  v_errm varchar2(64);
BEGIN
 
  SELECT dba_log.log_seq.NEXTVAL INTO v_log_seq FROM dual;
  INSERT INTO dba_log.log (id_log, rotina) VALUES (v_log_seq,'tablespace_load');
 
  INSERT INTO dba_log.tablespace (nome, maximo, alocado, utilizado, livre)
    SELECT
      u.tablespace_name,
      m.maximo,
      m.alocado,
      u.utilizado,
      l.livre
      FROM
        (SELECT tablespace_name, CEIL (SUM (bytes) / 1048576) utilizado
           FROM dba_segments
           GROUP BY tablespace_name) u,
        (SELECT
           tablespace_name,
           CEIL (SUM (bytes) / 1048576) alocado,
           CEIL (SUM (DECODE (autoextensible, 'NO', bytes, maxbytes)) / 1048576) maximo
           FROM dba_data_files
           GROUP BY tablespace_name) m,
        (SELECT
           tablespace_name,
           CEIL (SUM (bytes) / 1048576) livre
           FROM dba_free_space
           GROUP BY tablespace_name) l
      WHERE
        l.tablespace_name = u.tablespace_name AND
        l.tablespace_name = m.tablespace_name
    ;
  UPDATE dba_log.log SET fim = SYSDATE WHERE id_log = v_log_seq;
  COMMIT;
 
  EXCEPTION
    WHEN OTHERS THEN
      v_code := SQLCODE;
      v_errm := SUBSTR(SQLERRM, 1 , 64);
      INSERT INTO dba_log.erros (id_log, cod_erro, mensagem) VALUES (v_log_seq, v_code, v_errm);
END;
/
 
CREATE TABLE dba_log.objeto_qt (
    tipo        varchar2(19),
    esquema     varchar2(30),
    STATUS      varchar2(7),
    qt          NUMBER(5) NOT NULL,
    DATA        DATE DEFAULT SYSDATE,
    CONSTRAINT objeto_qt_pk PRIMARY KEY (tipo, esquema, STATUS, DATA)
);
 
CREATE OR REPLACE PROCEDURE dba_log.objeto_qt_load AS
  v_log_seq NUMBER(10);
  v_code NUMBER(10);
  v_errm varchar2(64);
BEGIN
  SELECT dba_log.log_seq.NEXTVAL INTO v_log_seq FROM dual;
  INSERT INTO dba_log.log (id_log, rotina) VALUES (v_log_seq,'objeto_qt_load');
 
  INSERT INTO dba_log.objeto_qt (tipo, esquema, STATUS, qt)
    SELECT b.tipo, b.esquema, b.STATUS, b.qt
      FROM
        (SELECT object_type tipo, owner esquema, STATUS FROM dba_objects
           MINUS
           SELECT tipo, esquema, STATUS FROM dba_log.objeto_qt) a,
        (SELECT object_type tipo, owner esquema, STATUS, COUNT(*) qt
           FROM dba_objects
           GROUP BY owner, object_type, STATUS) b
      WHERE
        a.tipo = b.tipo AND
        a.esquema = b.esquema AND
        a.STATUS = b.STATUS
      ORDER BY esquema, tipo, STATUS
   ;
 
  INSERT INTO dba_log.objeto_qt (tipo, esquema, STATUS, qt)
    SELECT o.tipo, o.esquema, o.STATUS, o.qt
      FROM
        dba_log.objeto_qt q,
        (SELECT object_type tipo, owner esquema, STATUS, COUNT(*) qt
           FROM dba_objects
           GROUP BY owner, object_type, STATUS) o,
        (SELECT tipo, esquema, STATUS, MAX(DATA) DATA
           FROM dba_log.objeto_qt
           GROUP BY tipo, esquema, STATUS) d
      WHERE
        o.tipo = q.tipo AND
        o.tipo = d.tipo AND
        o.esquema = q.esquema AND
        o.esquema = d.esquema AND
        o.STATUS = q.STATUS AND
        o.STATUS = d.STATUS AND
        q.DATA = d.DATA AND
        o.qt != q.qt
        ORDER BY o.esquema, o.tipo, o.STATUS
  ;
  UPDATE dba_log.log SET fim = SYSDATE WHERE id_log = v_log_seq;
  COMMIT;
 
  EXCEPTION
    WHEN OTHERS THEN
      v_code := SQLCODE;
      v_errm := SUBSTR(SQLERRM, 1 , 64);
      INSERT INTO erros (id_log, cod_erro, mensagem) VALUES (v_log_seq, v_code, v_errm);
END;
/
 
CREATE TABLE dba_log.objeto_invalido (
    tipo        varchar2(19),
    esquema     varchar2(30),
    nome        varchar2(128),
    DATA        DATE DEFAULT SYSDATE,
    CONSTRAINT objeto_invalido_pk PRIMARY KEY (tipo, esquema, nome, DATA)
);
 
CREATE OR REPLACE PROCEDURE dba_log.objeto_invalido_load AS
  v_log_seq NUMBER(10);
  v_code NUMBER(10);
  v_errm varchar2(64);
 
BEGIN
  SELECT dba_log.log_seq.NEXTVAL INTO v_log_seq FROM dual;
  INSERT INTO dba_log.log (id_log, rotina) VALUES (v_log_seq,'objeto_invalido_load');
  INSERT INTO dba_log.objeto_invalido (tipo, esquema, nome)
    SELECT object_type tipo, owner esquema, object_name nome
      FROM dba_objects
      WHERE STATUS != 'VALID'
    MINUS
    SELECT tipo, esquema, nome FROM dba_log.objeto_invalido
  ;
  UPDATE dba_log.log SET fim = SYSDATE WHERE id_log = v_log_seq;
  COMMIT;
 
  EXCEPTION
    WHEN OTHERS THEN
      v_code := SQLCODE;
      v_errm := SUBSTR(SQLERRM, 1 , 64);
      INSERT INTO dba_log.erros (id_log, cod_erro, mensagem) VALUES (v_log_seq, v_code, v_errm);
END;
/
 
CREATE TABLE dba_log.objeto_tamanho (
    tipo        varchar2(19),
    tablespace  varchar2(30),
    esquema     varchar2(30),
    nome_part   varchar2(112),
    tamanho     NUMBER(8),
    extents     NUMBER(5),
    num_reg     NUMBER(10),
    DATA        DATE DEFAULT SYSDATE,
    CONSTRAINT objetos_tamanho_pk PRIMARY KEY (tipo, esquema, nome_part, DATA)
);
 
CREATE OR REPLACE PROCEDURE dba_log.objeto_tamanho_load AS
  v_log_seq NUMBER(10);
  v_code NUMBER(10);
  v_errm varchar2(64);
 
BEGIN
 
  SELECT dba_log.log_seq.NEXTVAL INTO v_log_seq FROM dual;
  INSERT INTO dba_log.log (id_log, rotina) VALUES (v_log_seq,'objeto_tamanho_load');
 
  INSERT INTO dba_log.objeto_tamanho 
    (tipo, tablespace, esquema, nome_part, tamanho, extents, num_reg)
    SELECT b.tipo, b.tablespace, b.esquema, b.nome_part, b.tamanho, b.extents, b.num_reg
    FROM
      (SELECT
         segment_type tipo,
         owner esquema,
         NVL2(partition_name, segment_name || '/' || partition_name, segment_name) nome_part
         FROM dba_segments
      MINUS
      SELECT tipo, esquema, nome_part FROM dba_log.objeto_tamanho) a,
      (SELECT
        s.segment_type tipo,
        s.tablespace_name tablespace,
        s.owner esquema,
        NVL2(s.partition_name, s.segment_name || '/' || s.partition_name, s.segment_name) nome_part,
        CEIL(s.bytes/1048576) tamanho,
        s.extents,
        t.num_rows num_reg
        FROM
          dba_segments s,
          dba_tables t
       WHERE
         (s.bytes > 67108864 OR s.extents > 50 OR t.num_rows > 1000000) AND
          s.owner = t.owner (+)AND
          s.segment_name = t.TABLE_NAME (+)) b
    WHERE
      a.tipo = b.tipo AND
      a.esquema = b.esquema AND
      a.nome_part = b.nome_part
  ;    
 
  INSERT INTO dba_log.objeto_tamanho 
    (tipo, tablespace, esquema, nome_part, tamanho, extents, num_reg)
    SELECT o.tipo, o.tablespace, o.esquema, o.nome_part, o.tamanho, o.extents, o.num_reg
      FROM
        dba_log.objeto_tamanho l,
        (SELECT tipo, esquema, nome_part, MAX(DATA) DATA
          FROM dba_log.objeto_tamanho
          GROUP BY tipo, esquema, nome_part) d,
        (SELECT
          s.segment_type tipo,
          s.tablespace_name tablespace,
          s.owner esquema,
          NVL2(s.partition_name, s.segment_name || '/' || s.partition_name, s.segment_name) nome_part,
          CEIL(s.bytes/1048576) tamanho,
          s.extents,
          t.num_rows num_reg
          FROM
            dba_segments s,
            dba_tables t
          WHERE
            (s.bytes > 67108864 OR s.extents > 50 OR t.num_rows > 1000000) AND
            s.owner = t.owner (+)AND
            s.segment_name = t.TABLE_NAME (+)) o
      WHERE
        l.tipo = d.tipo AND
        l.tipo = o.tipo AND
        l.esquema = d.esquema AND
        l.esquema = o.esquema AND
        l.nome_part = d.nome_part AND
        l.nome_part = o.nome_part AND
        l.DATA = d.DATA AND
        (o.tamanho != CEIL(l.tamanho) OR l.extents != o.extents OR l.num_reg != o.num_reg)
      ORDER BY o.esquema, o.tablespace, o.tipo DESC
  ;
  UPDATE dba_log.log SET fim = SYSDATE WHERE id_log = v_log_seq;
  COMMIT;
 
  EXCEPTION
    WHEN OTHERS THEN
      v_code := SQLCODE;
      v_errm := SUBSTR(SQLERRM, 1 , 64);
      INSERT INTO dba_log.erros (id_log, cod_erro, mensagem) VALUES (v_log_seq, v_code, v_errm);
END;
/

Agendamento

Se você estiver utilizando o Oracle 10g ou superior, deve preferir usar o SCHEDULER:

BEGIN
 
  DBMS_SCHEDULER.CREATE_WINDOW(
    window_name=>'SYS.MONTH_START_WINDOW',
    resource_plan=>'SYSTEM_PLAN',
    start_date=>SYSTIMESTAMP,
    duration=>numtodsinterval(240, 'minute'),
    repeat_interval=>'FREQ=MONTHLY;BYMONTHDAY=1;BYHOUR=3',
    end_date=>null,
    window_priority=>'LOW',
    comments=>'Start of the month window for maintenance task'
  );
 
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'DBA_LOG.TABLESPACE_LOAD_MENSAL',
    job_type => 'STORED_PROCEDURE',
    job_action => 'DBA_LOG.TABLESPACE_LOAD',
    schedule_name => 'SYS.MONTH_START_WINDOW',
    enabled => TRUE
  );
 
  DBMS_SCHEDULER.SET_ATTRIBUTE(
    name => '"DBA_LOG"."TABLESPACE_LOAD_MENSAL"',
    attribute => 'job_priority',
    VALUE => 4
  );
 
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'DBA_LOG.OBJETO_TAMANHO_LOAD_SEMANAL',
    job_type => 'STORED_PROCEDURE',
    job_action => 'DBA_LOG.OBJETO_TAMANHO_LOAD',
    schedule_name => 'SYS.WEEKEND_WINDOW',
    enabled => TRUE
  );
 
  DBMS_SCHEDULER.SET_ATTRIBUTE(
    name => 'DBA_LOG.OBJETO_TAMANHO_LOAD_SEMANAL',
    attribute => 'job_priority',
    VALUE => 4
  );
 
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'DBA_LOG.OBJETO_INVALIDO_LOAD_DIARIO',
    job_type => 'STORED_PROCEDURE',
    job_action => 'DBA_LOG.OBJETO_INVALIDO_LOAD',
    schedule_name => 'SYS.WEEKNIGHT_WINDOW',
    enabled => TRUE
  );
 
  DBMS_SCHEDULER.SET_ATTRIBUTE(
    name => 'DBA_LOG.OBJETO_INVALIDO_LOAD_DIARIO',
    attribute => 'job_priority',
    VALUE => 4
  );
 
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'DBA_LOG.OBJETO_QT_LOAD_DIARIO',
    job_type => 'STORED_PROCEDURE',
    job_action => 'DBA_LOG.OBJETO_QT_LOAD',
    schedule_name => 'SYS.WEEKNIGHT_WINDOW',
    enabled => TRUE
  );
 
  DBMS_SCHEDULER.SET_ATTRIBUTE(
    name => 'DBA_LOG.OBJETO_QT_LOAD_DIARIO',
    attribute => 'job_priority',
    VALUE => 4
  );
 
END;
/

Se estiver utilizando o Oracle 9i ou inferiro, terá que utilizar os JOBs para agendar a coleta de dados:

VARIABLE jobno NUMBER;
BEGIN
  DBMS_JOB.SUBMIT(:jobno, 'BEGIN DBA_LOG.OBJETO_QT_LOAD; END;',
    TRUNC(SYSDATE) + 1/24, 'TRUNC(SYSDATE) + 1/24 + 30');
  COMMIT;
END;
/
 
VARIABLE jobno NUMBER;
BEGIN
  DBMS_JOB.SUBMIT(:jobno, 'BEGIN DBA_LOG.TABLESPACE_LOAD; END;',
    TRUNC(SYSDATE) + 1/24, 'TRUNC(SYSDATE + 30,''MONTH'') + 1/24');
  COMMIT;
END;
/
 
VARIABLE jobno NUMBER;
BEGIN
  DBMS_JOB.SUBMIT(:jobno, 'BEGIN DBA_LOG.OBJETO_TAMANHO_LOAD; END;',
    TRUNC(SYSDATE) + 1/24, 'NEXT_DAY(TRUNC(SYSDATE), ''SATURDAY'') + 1/24');
  COMMIT;
END;
/
 
VARIABLE jobno NUMBER;
BEGIN
  DBMS_JOB.SUBMIT(:jobno, 'BEGIN DBA_LOG.OBJETO_INVALIDO_LOAD; END;',
    TRUNC(SYSDATE) + 1/24, 'TRUNC(SYSDATE) + 25/24');
  COMMIT;
END;
/
 
VARIABLE jobno NUMBER;
BEGIN
  DBMS_JOB.SUBMIT(:jobno, 'BEGIN DBA_LOG.OBJETO_QT_LOAD; END;',
    TRUNC(SYSDATE) + 1/24, 'TRUNC(SYSDATE) + 25/24');
  COMMIT;
END;
/

Conclusão

Com os dados coletados nas tabelas, você só precisa agora exercitar um pouco do seu conhecimento de SQL para fazer consultas criativas e gerar relatórios dos mais diversos e entregar para o seu chefe no final do ano. Não, adianta nada criar os objetos agora e tentar fazer mágica. Após um anos, você poderá observar com alguma precisão a sazonalidade das aplicações e fazer boas projeções. Que tal começar o ano com um mínimo de coleta de dados na sua base? Quando a turma do ITIL bater na sua porta, algumas coisas já estarão encaminhadas para o seu lado.

Frase do Dia

Um DBA bonzinho é um DBA desempregado!

Explico: O DBA (Database Administrator) é o responsável em última instância em garantir que os dados da empresa não se percam, não se corrompam e estejam sempre disponíveis. Você acha que consegue isso sendo bonzinho? Oh não… tudo (usuários, aplicações, chefes, desenvolvedores, a previsão do tempo, as eleições nos EUA, a bolsa de valores) conspira para que seus dados desapareçam, se estraguem ou que todo o servidor vá para o vinagre.

OBS: Quer ver um DBA feliz? Leia a documentação!!!

Enterprise Solid State Drives, você não viu ainda?

Quando eu era um garoto, meu pai me levava nas feiras de informática que ocorriam no Anhembi, ainda no final da década de 80. Eram meus primeiros contatos com a informática. Eu fazia meus primeiros programas em BASIC num CP400 e gravava tudo em fitas cassetes. Foi um alívio quando usei pela primeira vez um disquete no Apple IIe. Era algo realmente incrível. Então veio o primeiro PC com um incrível HD de 20MB. Fantástico. Depois veio um moderno 486 que tinha um disco de fantásticos 200MB. Logo foi trocado por um de 2GB, 6GB e quando pisquei o olho já usava um disco de 40GB. Hoje os dois discos SATA de 200GB não parecem muito grandes…

Mas voltemos para os tempos das feiras de informática, antes da FENASOFT surgir e depois sumir. Um dia vimos as primeiras memórias flash ainda como protótipo numa destas feiras… Meu pai olhou para aquilo e pensou: “Hum, sem partes móveis? Mais rápido e mais confiável… isso ainda vai aposentar os discos rígidos em menos de 10 anos”. Bom, naquele tempo eu já fazia o curso Técnico em Eletrônica e via as memórias EEPROM e UVPROM e também as “memórias CMOS”. Para um mercado que tinha saído das ROMs puras há pouco… tudo já parecia fantástico. Mas de fato as memórias FLASH foram chegando. Primeiro os disquetes foram saindo e sua morte foi enfim anunciada com os primeiro iMacs sem unidades de disquetes e com as novas portas USB! Os gravadores de CD também inundavam o mercados e padrões proprietários que melhoravam os disquetes como os ZIP Disks afundaram. Então vieram os pendrives, 128K, 512K, 1GB, 4GB e já temos os de 32GB. Em 2007 os notebooks entraram na dança e os primeiros HDs finalmente foram saindo de cena.

Até aí, ninguém decretou o fim dos HDs… os HDs continuam firme e forte. Os IDEs e SCSI deram lugar aos modenos SATA e SAS e vão evoluindo em capacidade e velocidade. Os HDs SATA de 10Krpm e os SAS de 15Krpm se tornaram comuns. Controladoras SATA com RAID 0, 1 e 10 já são comuns. Controladoras SAS com capacidade para dezenas de discos, baterias para o cache estão a pleno vapor. Sem contar com os Storages que são mais flexíveis usando interfaces iSCSI, Fibre Channel e InfiniBand e flexibilidade para usar discos Fibre Channel, SAS e até SATA. A indústria de discos rígidos continua a pleno vapor. Com a excessão dos notebooks, os desktops e servidores parecem estar com seu mercado garantido. Até quando?

É claro que os notebooks, subnotebooks, palms, mp3 e outros gadgets estão inundando um mercado que se acostuma com a ausência dos discos rígidos. Mas quando se fala em performance e confiabilidade, as memórias flash são em geral descartadas. Elas tem por tradição seram mais lentas e terem a mania de ir perdendo alguns bits com o tempo. Por outro lado, há uma demanda cada vez maior por performance. Quando eu escrevi o meu artigo sobre PostgreSQL, discos & cia eu fui pesquisando alguns dados para melhorar o artigo. Ao fazer uma busca por IOPS eu tive que fazer uma longa pausa na escrita do artigo. Algo mudou no ar. Não é uma coisa qualquer… isso é grande, é uma “mudança disruptiva”. Daqui para frente, após todo esse blábláblá, vou tentar explicar o que se passa nos bastidores.

Tratar grandes volumes de dados nem sempre foi a trarefa principal dos computadores. A IBM nasceu construindo máquinas que pudessem tratar grandes volumes de dados, mas estes não eram computadores, eram máquinas de tabular dados. O primeiro sucesso foi com o censo dos Estados Unidos em 1890 e depois em 1900. Nascia a época dourada dos cartões perfurados para o tratamento de grandes volumes de dados. Os primeiros computadores tratavam principalmente de cálculos complexos. Foi o surgimento dos discos magnéticos que propiciou o algo parecido com o que hoje chamamos de banco de dados. A primeira unidade de discos rígidos foi o IBM 305 RAMAC em 1956 com seus 5MB em uma unidade de disco rígido com quase uma tonelada e do tamanho de uma lavadora de roupas . Em 1965 já vemos o surgimento do CODASYL, a primeira tentativa de padronizar o acesso a dados, que mais tarde deu origem ao COBOL. A questão aqui é que discos rígidos e bancos de dados nasceram juntos e cresceram juntos. Não haveria como os bancos de dados crescerem se não houvesse um correspondente aumento de capacidade e velocidade dos discos. Os custo, é claro, também caiu muito.

Vejamos uma comparação entre o IBM 1311 lançado em 1961 e um disco SAS atual.

IBM 1311 (1961) Disco SAS (2007)
Capacidade 28MB 300GB
Número de Discos 20 4
Diâmetro do Disco 18″ 3,5″
Velocidade de Rotação 1,8Krpm 15Krpm
Taxa de transferência 90KB/s 300KB/s
Custo US$115.500 US$300

Enfim o que mudou? Discos menores, com maior densidade magnética, maior velocidade de rotação e menor custo. Claro que há muito mais que isso. Há interfaces como SATA, SAS, FC, InfiniBand, vários tipos de RAID, cache e uma infinidade de tecnologias destinadas a melhorar a performance, confiabilidade e preço dos discos. Mas, mesmo com enorme ganho nestas 3 áreas, em algum momento da história, os discos deixaram de acompanhar o rítimo de desenvolvimento dos processadores quanto ao desempenho. O custo dos storages em grandes bancos de dados é cada vez mais significativo no custo total do hardware. Enquanto se mensurava o custos dos discos em US$/GB, hoje se mede também em US$/IOPS. Ou seja, não se trata mais apenas de conseguir espaço em disco. Se trata também manter um volume de operações de leitura e gravação por segundo adequada as exigências do seu banco de dados.

Bom, para o mercado de Banco de Dados, as demandas parecem que cresceram mais que a tecnologia. Não são apenas as bases com mais de 10TB que assustam os DBAs. Em apenas um Rack de 19″ podemos ter 10TB com RAID e tudo o mais. Claro que não vai sair barato. Mas discos grandes não são tão caros. Um disco SAS de 1TB não custa muito. Mas e para se conseguir 10 mil IOPS? Sim, aí você terá problemas. Discos rápidos são caros. Você vai precisar de um RAID 10 muitos discos velozes para conseguir alguma coisa próxima a 10 mil IOPS. Os modernos storages atuais podem ter atingir mais de 200 mil IOPS. E mais, pode ser que você use estes discos apenas para guardar seus logs de transação do banco de dados. Parece um exageiro, mas em bases com fortes demandas OLTP isso não é nenhum absurdo. Não é a toa que discos de 36GB não saem do mercado, mesmo com os discos de 1TB disponíveis.

Hoje se fala de “unidades de estado sólido” ou Solid State Drives, ou ainda apenas SSD. Apesar de serem internamente completamente diferentes das unidades de discos rígidos, para o SO, se comportam de forma idêntica. Possuem sistemas de arquivos, partições e tudo o mais. De fato, a idéia é poder trocar um disco rígido por memórias de estado sólido de forma natural. O conector, a interface (SATA ou SAS) e as características lógicas são as mesmas. Isto realmente torna as coisas muito mais simples. Na verdade, uma disco de estado sólido pode ter inclusive o mesmo tamanho de um disco de 3.5″, se encaixando normalmente no lugar de um disco rígido. Vejam a foto abaixo. Trocar uma unidade de disco rígido e inserir um SSD não parece uma tarefa nada assustadora.

HD X SSD

Bom, vamos com calma agora. Eu sei que tenho falado muito até agora, mas leia isso com atenção. Todos devem lembrar das diferenças entre a RAM e a ROM:

  • Os dados na RAM são volateis enquanto os dados na ROM são persistentes;
  • As memórias ROM podem ser do tipo ROM, PROM, EEPROM ou Flash
    • A ROM pura vem gravada de fábrica e nunca pode ter seu conteúdo gravado;
    • A PROM pode ser gravada uma única vez por um processo especial de queima de microfusíveis;
    • A EPROM ou UVPROM que podia ser apagada expondo o chip a luz ultra violeta e depois regravada;
    • A EEPROM que podia se apagada e regravada por meio de pulsos elétricos;
    • A Memória Flash que pode apagar apenas uma parte da sua memória e regrava-la. Ela pode ser do tipo NOR ou NAND. As memórias Flash também são chamadas de RAM não volátil ou NVRAM. Mas sua origem histórica vem do ramo das ROMs.
      • A Flash do tipo NOR veio a substituir as memórias PROM, EPROM e EEPROM;
      • A Flash do tipo NAND é adequada para leituras e gravações em bloco como em memórias de massa, AKA. discos. A Flash de tipo NAND são hoje de dois tipos:
        • A MLC pode armazenar mais de um bit por célula, possuindo um custo por bit mais baixo. A memória Flash MLC é a utilizada em pendrives e cartões de memória fartamente encontrados no mercado.
        • A SLC armazena apenas um bit por célula, tendo menor densidade e maior custo. Por outro lado ela é mais rápida e tem uma vida útil maior.
  • As memórias RAM podem ser do tipo dinâmicas ou DRAM ou estáticas SRAM:
    • A SRAM utiliza uma estrutura de transistors conhecida como FLIP-FLOP para armazenar os dados, são mais caras e podem ser to tipo:
      • TTL que é a mais rápidas e a que consome mais energia. Utilizada sempre em buffers e caches;
      • CMOS que é lenta mas é a que menos consome energia quando está em repouso. Utilizada para armazenar os dados do setup, por exemplo;
    • A DRAM é mais barata e possui alta densidade, é utilizada nas memórias DDR;

Violin 1010Bom, isto só para ter um panorama simplificado das memórias utilizadas comercialmente hoje em dia. Siga os links acima para ter mais detalhes. Ocorre que na maioria das vezes em que estamos falando de SSD, estamos falando de dispositivos que utilizam memória Flash MLC. Estes são os discos com preços competitivos, feitos para competir com discos SATA. É para este camimnho que os notebooks topo de linha estão migrando massivamente e que devem aposentar os HDs rapidamente neste segmento. Mas há uma nova geração SSD feitos para competir no quesito desempenho.

Em agosto de 2007, uma empresa anunciou um dispositivo que pode ser conectado numa porta PCIe de 20GB/s. Com 2U e 504GB de memória este dispositivo alcança 3 milhões de IOPS. E não é só: taxas de transferência de 1400MB/s em leitura e 1000MB/s em gravação. Qual o milagre? Simples, não há discos nem flash… e sim a boa e velha memória SDRAM. Bom… é óbvio que esse pessoal não espera que a energia acabe. Mas de toda forma o Violin 1010 quando ligado num bom nobreak oferece um desempenho incrível com menor consumo de energia, baixo custo e sem exigir mudanças na sua aplicação. Veja os números você mesmo e imagine sua aplicação ficando 30 a 60 vezes mais rápida de uma hora para outra!

No final de setembro, a Fusion-IO lança uma placa PCIe 4x com 640GB utilizando memória flash NAND SLC e com um software novo capaz de diminuir as deficiências das memórias flash. A performance? 10 mil IOPS e 800 MB/s. Em novembro a BitMicro anuncia a venda de SSDs com memória flash NAND SLC de 1,6TB mas utilizando a interface Fibre Channel.Então em Janeiro de 2008, a Texas Memory Systems publica seus testes com o RAM-SAN 400. O RAM-SAN 400 vem de uma linhagem de storages que utilizam memórias DDR RAM para armazenar dados emulando discos rígidos. Neste sentido o RAM-SAM é parecido com a solução da BitMicro por se portar como um Storage, por outro lado é parecido com o Violin 1010 que utiliza RAM. A diferença é que o RAM-SAN tem 3 baterias internas e um HD internamente. Se a energia acabar, as baterias entram em ação e gravam todos os dados no HD. Outro detalhe é que o RAM-SAM já tem esta solução há algum tempo no mercado, sendo homologado pela IBM, Microsoft e SUN… e com a publicação dos seus testes no Storage Performance Council (SPC) que é para o storage o que o TPC é para os bancos de dados.
RAM-SAN 400

O RAM-SAN 400 é um storage com até 8 portas Fibre Channel e até 128GB de memória RAM. O os testes no SPC tiveram o seguinte resultado: mais de 291 mil IOPS ao custo total de 194785 US$ ou seja: US$0,67 US$/IOPS . Vamos comparar com outro teste recente no mesmo site? O teste da 3PAR InServ® T800 Storage Server alcança quase 225 mil IOPS ao custo de mais de 2 milhões de dólares ou 9,3 US$/IOPS. O resultado é um desempenho 13 vezes mais baixo. O milagre? Enquanto o RAM-SAM usa um storage de 3U e 128GM de memória SDRAM, o T800 usa 5 racks de 44U, e tem 77TB com 4 x 320 discos fibre channel de 146GB cada. Agora imagine a diferença de consumo de energia?

OK, o RAM-SAN é comprovadamente uma solução viável. Mas foi quando a EMC lançou também em janeiro de 2008 que o mercado entrou em polvorosa definitivamente. A solução é simples. Você pode utilizar o storage topo de linha da EMC o Symmetrix e escolher utilizar alguns SSDs no lugar de discos convencionais. Resultado? Um nome de peso como o da EMC com um storage de alto nível e o melhor dos dois mundos: espaço com discos SAS e velocidade com discos SSD. A EMC apostou em discos SSD com memórias FLASH NAND SLC, assim como a Fusion-IO e a BitMicro. A diferença é que você tem integrado ao SSD, agora chamado de “Enterprise Flash Drive” junto com um storage reconhecido no mercado. A entrada da EMC neste mercado pode ser comparado com a entrada da IBM no segmento de microcomputadores. Ok, talvez eu esteja exagerando um pouco, talvez não. O fato é que a EMC alega que seus SSDs tem 30 pelo menos vezes mais IOPS que os discos mais rápidos disponíveis e um ciclo de vida maior.

São notícias realmente animadoras. Os SSDs com memórias flash NAND SLC utilizam mecanismos mais sofisticados para minimizar a possibilidade de perda de dados. E não parou por aí… em junho a HP e Fusion-IO anunciam que vão adaptar os discos SSD da Fusion-IO para os sistemas Blade da HP. A Texas Memory Systens criou o RAM-SAN 440 com memórias DDR2 e mais velocidade e o RAM-SAN 500 utilizando agora memória flash NAND SLC também. E assim, todos estão correndo atrás da nova onda. Uma virada deste tipo pode dar a possibilidade para novas empresas crescerem e grandes empresas que venham a perder o bonda da história sumirem do mapa. Ainda é tudo muito incerto. Vejamos como está o mercado hoje:

  • Alguns apostam em placas PCI para conectar diretamente as memórias. Faz sentido… para que eu preciso ser uma caríssima controladora quando eu posso me conectar diretamente ao barramento do sistema. Muita coisa nova pode surgir daí;
  • Por outro lado, ter uma unidade onde eu possa retirar um disco e colocar um SSD na mesma baia parece algo muito interessante, tanto num desktop quanto num caríssimo storage;
  • Os SSDs baseados em memórias Flash NAND MLC vão continuar substituindo os HDs SATA em notebooks, desktops e há quem já fale nestes brinquedinhos como o futuro dos CPDs verdes. Tudo o que sabemos é que o preço está caindo enquanto a capacidade, velocidade e confiabilidade vem aumentando rapidamene;
  • Os SSDs baseados em memórias Flash NAND SLC são a opção mais confiável para conseguir dispositivos rápidos. É nesta direção que a maioria das pesquisas estão se concentrando. Conseguir 100 mil IOPS parece um bom ganho para muitos;
  • As soluções SSD baseadas em DRAM são o que há de mais rápido no mercado. O RAM-SAN parece que está conquistando muitos adeptos com um custo atraente. O RAM-SAN 440 atingiu mais de 600 mil IOPS enquanto o Violin conseguiu mais de 3 milhão de IOPS. Enquanto no RAM-SAN você acaba tendo que confiar nas baterias redundantes do equipamento, no Violin, o abacaxi está inteiramente na sua mão. Performance sempre tem preço.

É cedo ainda, mas é real. Está acontecendo e quem está no limite do desempenho está convidado a experimentar as novas tecnologias SSD para o mercado de alto desempenho transacional. Eu gostaria muito de poder testar um brinquedinho destes. Seria interessante testar diferentes particionamentos utilizando SSDs de alto desempenho. Outro desafio seria rever a parte de tuning nos SGDBs. O otimizador de consultas está sempre privilegiando leituras sequenciais e atribuindo um custo diferente para operações de leitura/escrita sequencial/randômica. É claro que não dá para sonhar colocar todos os seus tablespaces num caro SSD de alto desempenho. O fato de colocar apenas os logs transacionais e tablespaces específicos vai exigir novamente mais habilidade dos DBAs para tirar todo proveito desta nova tecnologia. Particularmente eu já vejo os DBAs bem aparelhados com o PostgreSQL, uma vez que as estimativas de custos são parametrizadas. O que pode acontecer é ter que fazer ajustes específicos para operações que utilizam ou não tablespaces armazenadas em SSD. De qualquer forma, um futuro mais rápido surge no nosso horizonte.

Qual meu maior medo nisso tudo? Que os desenvolvedores continuem embarcando cegamente na onda dos ORMs e quando a performance gritar… fazer o que todo mau programador adora fazer: aumentar a performance do hardware ao invés de concertar a aplicação. A aplicação sentou o banco? Compra uns SSDs que rezolve….

Manifesto pelo Dia do DBA

Assim que a empresa começou a crescer veio a necessidade de trazer alguns computadores para a equipe administrativa. Os usuários estavam felizes com seus computadores novos fazendo seus textos, planílhas e coisa e tal. Mas vira e mexe alguém tinha uma dúvida de como fazer isso ou aquilo. A impressora não funcionava, apareciam vírus por todo lado e a os computadores travavam. Então vieram os pioneiros de TI fazendo suporte aos usuários finais.

A empresa começou a crescer mais computadores foram comprados. Mais gente queria acessar a Internet e o protocolo DPCDPL (Disquete Para Cá e Disquete Para Lá) começou a complicar a vida demais das pessoas. Então surgiram os primeiros servidores, com o primeiro firewall, o primeiro servidor de arquivos e impressão. Então eis que surge o sysadmin para botar órdem nisso tudo, inclusive no pessoal de suporte.

Um belo dia alguém teve a ideia de desenvolver um sistema para tocar algumas partes vitais da empresa e vieram os primeiros desenvolvedores para criar o sistema. Logo os sistemas se multiplicaram e surgiu um gestor para o setor de TI. Com o orçamento reforçado, decidiram implantar um ERP e os analistas começaram a brotar aos montes.

Não demorou muito para perceberem que as informações estavam desencontradas entre os sistemas e um dia aconteceu o pior: perderam um banco de dados. Surgiu finalmente o DBA para arrumar os bancos de dados e dar jeito nos backups e recuperar o que podia da catástrofe anunciada. Outros cargos apareceram, o gerente de projetos, o AD e por aí vai.

Acontece que o DBA vira e mexe tomava cerveja na sexta-feira com o sysadmin. Qual foi a surpresa do DBA ao descobrir que o sysadmin tinha um dia em sua homenagem… a última sexta-feira de julho. É claro que isso parece desculpa para juntar o povo para tomar cerveja, senão porque escolher a sexta como dia de comemoração? bom, meus caros… proponho que a 1ª sexta-feira de Agosto seja o dia do DBA. Sim, você pode convidar o sysadmin para beber também!

Então, o convite está feito: vamos comemorar o “Dia do DBA” amanhã, ok?