segunda-feira, 19 de novembro de 2012

Oracle 12c: Pluggable Databases

Antes de mais nada, preciso dizer que a informação deste post não é 100% confiável. O que vem a seguir é uma coletânea de informações de diversas fontes: palestras do último Oracle Open World, perguntas e respostas de participantes nestas mesmas palestras, perguntas que eu mesmo fiz a especialistas nos "Demo Grounds", posts do Fórum da Oracle, artigos já publicados na internet, entre outras. Questões sobre as quais ainda não encontrei informação alguma estão na última seção: Dúvidas.

Posto isso, vamos à novidade de maior impacto no Oracle Database desde... desde... bem, desde sempre, eu acho. Trabalho com Oracle desde a versão 7.1 e não consigo me lembrar de nada tão radical. Objetos, Java, Flashback, ASM, Editions, Replay... Nada mexeu tanto com a estrutura do software como este novo sistema de Containers e Plugged Databases. RAC, talvez ? Talvez, pois RAC trouxe o cenário "N instâncias e 1 database", e esta nova feature traz algo que poderia ser interpretado como "1 instância e N databases".

Introdução: O Problema


O que o mercado chama vulgarmente de "Banco Oracle" é tipicamente uma estrutura monolítica, criada para suportar aplicações grandes, enormes ou gigantescas. Você tem uma instância, que é um conjunto de processos no sistema operacional associado a algumas áreas de memória; você tem um database, que é um conjunto de diversos arquivos em disco. Os dois juntos formam um "Oracle Server", que é o nome correto. Vou manter esse nome em inglês para que não haja confusão com a palavra "servidor", que normalmente significa hardware. Uma variação dessa estrutura é a solução de alta disponibilidade RAC (Real Application Clusters), em que temos várias instâncias para um mesmo database.

Criar um Oracle Server é uma atividade planejada, que envolve diversas decisões; o cenário mais comum em produção é ele que ocupe totalmente o hardware que o abriga, e muitos sistemas baseados em Oracle foram projetados com essa premissa. Um Oracle Server precisa ser administrado. Precisa de políticas de backup, previsão de crescimento, acompanhamento de seus logs de alerta, atualização de estatísticas, entre dezenas de outras coisas.

Para aplicações pequenas e médias, existem dois cenários comuns:

  • Criar diversos Oracle Servers no mesmo hardware (com ou sem virtualização).
  • Colocar diversas aplicações no mesmo Oracle Server, uma em cada "schema/owner/usuário".

A primeira opção cria um desperdício enorme de recursos, tanto de hardware quanto humanos. É comum ver um DBA administrando 200 Oracle Servers, o que deixa todos mal administrados. É comum uma aplicação sofrer quedas de desempenho porque outra aplicação está processando algo pesado ou fazendo backup, e é difícil apurar isso porque as ferramentas de diagnóstico tratam de Oracle Servers, elas não conseguem olhar para fora desse escopo.

A segunda opção nem sempre é viável, pois muitas aplicações foram desenhadas para ocupar seu próprio Oracle Server. Quando é viável, existe a questão da segurança: não é trivial garantir que uma aplicação não terá acesso aos dados de outra (afinal de contas, privilégios "ANY" e roles como "DBA" dão acesso a todos os schemas). É comum que o departamento ou a empresa cujos dados estão em jogo simplesmente não aceite a consolidação.

Agora vamos pensar no cenário da TI corporativa nesta segunda década do século XXI: Exadata, Consolidação, Virtualização, Nuvem. O mundo mudou e todos os sistemas têm que compartilhar recursos. Dentro de uma Exadata, sistemas grandes são automaticamente rebaixados a médios ou pequenos. Como lidar então com o desperdício de recursos ?

Pluggable Databases


Com o Oracle 12c, entram em cena os conceitos de "Container" e "Pluggable" databases, uma estrutura hierárquica de dois níveis. Um "container database" (CDB) pode ter entre 0 e 250 "filhos", que são os "pluggable databases" (PDBs). Do ponto de vista das aplicações, cada PDB é um "Oracle Server" completo, totalmente compatível com as versões anteriores.

Olhando de fora, entretanto, a coisa é bem diferente: a partir do sistema operacional, a impressão que se tem é que existe apenas uma instância. Você verá apenas um processo SMON, um PMON, um CKPT. A mesma coisa acontece com a memória: SGA e PGA são dimensionadas no CDB, para atender a ele e a todos os seus PDBs. Undo e Redo ? Também. As mesmas tablespaces de UNDO e os mesmos redo logs online atendem ao CDB e a todos os seus PDBs.

Segundo a Oracle, a economia de recursos permite um ganho de 5x ou mais em comparação com múltiplos Oracle Servers. Em outras palavras, esse mesmo hardware que hoje no 11g suporta 10 instâncias poderia suportar 50 delas no 12c. Digo "instâncias" porque esse fator se aplica obviamente aos recursos de memória. O storage ainda precisará ser cinco vezes maior.

Administração


A administração promete ser facilitada. Por exemplo, o RMAN poderá ser configurado para fazer o backup do CDB e tudo o que estiver abaixo em uma só operação, mas este backup servirá para recuperar qualquer PDB individualmente.

Outro exemplo, muito mais interessante: PDBs podem ser desplugados de um container e plugados em outro container !!! Isso facilitará a migração de databases para outra plataforma, para outro hardware e mesmo para novas versões. Imagino o que processo de upgrade para o 12cR2 será assim: instalar o novo software, criar um novo container e então trazer cada um de seus PDBs para plugar neste novo container.

Cópias de databases também serão mais simples. Veja como fica este cenário típico na vida de qualquer DBA: existe um Oracle Server chamado "app01", onde roda uma aplicação específica. A equipe de QA precisa de uma cópia por alguns dias, para fazer testes de uma nova funcionalidade. Hoje em dia precisamos criar um novo server "app02" e utilizar RMAN ou "data pump" para levar os dados de um para outro. Se "app01" fosse um PDB, o processo seria assim: conectado ao container, executar:

alter pluggable database app01 close;

alter pluggable database app01 open read only;

create pluggable database app02 from app01 
file_name_convert = ('/app01', '/app02');

alter pluggable database app02 open;

Feito. Tablespaces da aplicação, tabelas, objetos, roles, usuários, diretórios e tudo mais foram copiados e estão prontos para o uso. A cláusula "file_name_convert" faz a tradução dos caminhos dos datafiles; se os originais estavam em "/u04/oradata/app01" os novos estarão em "/u04/oradata/app02".

Outros Detalhes


Sistema de Arquivos


Na instalação default, os datafiles dos PDBs ficam em diretórios abaixo de seu CDB:

CDB1: /u04/oracle/oradata/cdb1/system01.dbf
PDB1: /u04/oracle/oradata/cdb1/pdb1/system01.dbf
PDB2: /u04/oracle/oradata/cdb1/pdb2/system01.dbf 
PDB3: /u04/oracle/oradata/cdb1/pdb3/system01.dbf 

Processos de Background


Como já vimos, os processos tradicionais no sistema operacional (pmon, smon, ckpt) aparentam ser todos do CDB. É muito provável que tenhamos novos processos para cuidar de aspectos que esta nova dimensão apresenta.

Segurança


Os privilégios dentro de um PDB se aplicam somente a este PDB. Aparentemente, o privilégio de SYSDBA em um CDB dá poder total sobre os PDBs. Podemos esperar novos privilégios, mais restritivos, no nível do container.

Dúvidas

  • Como serão divididos os recursos ? Será que teremos um novo Resource Manager que permita distribuir a carga entre os PDBs ?
  • Como ficam os parâmetros ? Se existe apenas um conjunto de processos, é razoável supor que haverá parâmetros que não podem ser alterados nos PDBs e assumem o valor de seu container ? Mais ainda, será que teremos parâmetros que só existem em CDBs ou em PDBs ?
  • Será que o padrão será deixar o Container Database vazio, sem dados de nenhuma aplicação ?
  • Como será o RAC 12c ? Clusters de CDBs, de PDBs ou ambos ?

Veja Também:

terça-feira, 6 de novembro de 2012

Chave Primária - "Natural" ou "Surrogate" ?

Sempre que se inicia a modelagem de um sistema, existe (ou pelo menos deveria existir) uma discussão sobre a questão das chaves primárias, baseada na seguinte pergunta: Devemos usar campos com significado de negócio - "Natural Keys" (RG, CPF, Matrícula, Apólice) ou números gerados artificialmente, sem significado fora do sistema - "Surrogate Keys" ?

Já trabalhei com sistemas nas duas abordagens e hoje defendo a segunda opção: chaves artificiais, sem relação alguma com o negócio; apresento aqui os prós e contras que me levaram a essa decisão.

Prós:
  • Chaves artificiais permitem alterações de negócio com menos impacto. Este é provavelmente o argumento mais importante. Chaves naturais estão sempre sujeitas a mudanças. Empresas se fundem, o governo adiciona mais um dígito, a lei muda. Sempre desconfie de um analista que diz que "esse campo não vai mudar nunca". Eu já tive que alterar uma informação (número de apólice) que era PK de uma tabela de 600 mil registros, com mais de 100 "descendentes" distribuídos em 11 níveis de dependência. Acredite, não é legal. Ou você acha impossível que amanhã ou depois o governo brasileiro resolva adicionar um dígito ou dois ao CPF ?
  • Chaves artificiais resultam em menos colunas nas tabelas. A opção das chaves naturais vem sempre acompanhada do uso de chaves compostas, o que leva à redundância da informação e ao desperdício de espaço.
  • Não ocorre o problema das FKs inúteis. Como não há chaves compostas, não existe a possibilidade de um dos campos ser NULL e outro não.
  • Não ocorrem updates nos campos da chave primária, portanto há menos chance de locks problemáticos. Aliás, updates em campos de chave primária violam o modelo relacional bom senso e não deveriam mesmo acontecer em hipótese alguma.
  • Como as chaves são de apenas um campo, e este campo é NUMBER, os joins são mais simples (para o desenvolvedor e para o otimizador) e mais rápidos.
  • O uso de chaves com apenas uma coluna facilita os cálculos para o otimizador de custo (que só sabe mesmo lidar com seletividade de múltiplas colunas no Oracle 11g release 2). Isso resulta em melhores decisões de planos de execução e portanto em melhor desempenho do sistema como um todo.
Contras:
  • Mais operações de join são necessárias para montar a informação para o usuário final. Isso pode ser resolvido de várias maneiras, sendo que "snapshots" ou "materialized views" são a opção mais popular hoje em dia.
  • Uma constraint a mais é necessária (do tipo "unique" nos campos da chave natural). 
  • Parte da integridade de negócio deixa de ser validada pelas FKs. Este é o maior ponto de atenção, pois o banco de dados não detectará anomalias como "pedido de um cliente com itens de outro cliente". Na prática, é difícil uma aplicação estável criar esse tipo de registro, mas processos de carga e migração podem fazê-lo facilmente. 

Veja Também:

O Problema da FK Inútil


Gostaria de esclarecer um comportamento não-intuitivo do Oracle (e de todos os SGBDs aderentes ao padrão ANSI/ISO SQL92), que pode levar a problemas de modelagem de dados e de consistência destes dados.

Imagine uma tabela XPTO, cuja PK é composta de dois campos: ID_XPTO e ID_EMPRESA. Agora imagine outra tabela ACME: (ID_ACME [PK], ID_XPTO [FK] e ID_EMPRESA [FK]). Em ACME, filha de XPTO, ID_XPTO e ID_EMPRESA estão ligados a XPTO por uma constraint do tipo FK, mas permitem valores NULL. Suponha que XPTO tem apenas um registro (1,100) e são inseridas em ACME as seguintes linhas:

1. ACME ( 1, 1, 100 );
2. ACME ( 2, 1, NULL );
3. ACME ( 3, NULL, 100 );
4. ACME ( 4, NULL, NULL );
5. ACME ( 5, 666, NULL );
6. ACME ( 6, NULL, 666 );

Quantas destas linhas serão aceitas ? TODAS ELAS. A presença do valor NULL desobriga o banco da validação da chave estrangeira, portanto devemos tomar o cuidado de adicionar uma constraint de check que garante que ou todos os valores da FK são nulos, ou nenhum é nulo:

ALTER TABLE ACME ADD CONSTRAINT CK_ACME_XXXX CHECK
  ((ID_XPTO IS NULL AND ID_EMPRESA IS NULL) OR (ID_XPTO IS NOT NULL AND ID_EMPRESA IS NOT NULL))

Atenção: Claro que a melhor opção seria deixar os campos em ACME como NOT NULL. A solução acima deve ser utilizada apenas se o requisito de negócio exigir que os campos permitam NULL.