Edition-Based Redefinition: a feature mais matadora do Oracle 11g R2
04/02/2010
Eu considero Edition-Based Redefinition a nova característica mais matadora do Oracle Database 11g Release 2. Em suma, é a capacidade de executar uma atualização de aplicações online. É também um recurso gigante, tão grande que vai demorar pelo menos três colunas para descrevê-lo. Vou começar em Como usar Edition-Based Redefinition afim de aplicar “patches” em sistemas.
Ao longo dos anos, o banco Oracle permite realizrmos muitas operações online, como:
- Modificar a maioria dos parâmetros (Apenas 90 dos 350 não são modificáveis online.)
- Reorganização de objetos (transformar uma tabela não particionada em uma particionada, recuperando um espaço livre, e assim por diante)
- Criar índices
- Aplicação de patches no Banco de dados com o Oracle Real Application Clusters
- Atualizar o banco de dados Oracle de release em release
O resultado é que quase todas mudanças em nível de banco de dados pode ser feito enquanto o banco está funcionando e realizando transações – com algumas raras excepções gritantes, como re-criar uma procedure, alterar triggers, adicionar grants, revoke de grant, e modificar views. Em suma, os objetos que constituem esse tipo de modificação não podiam ser modificadas, enquanto os usuários estavam utilizando. Se uma procedure estava sendo executada e um DBA tentou atualizar ela (CREATE OR REPLACE o código com o novo código mexido, afim de corrigir um bug), o DBA iria ficar esperando (BLOCKED) por essa pessoa até terminar sua execução.
Além disso, qualquer pessoa que tentou posteriormente executar uma procedure que o DBA está tentando substituir também ficaria bloqueado pelo DBA. E na maioria dos casos, o DBA não modifica apenas uma única procedure, mas muitas, e o CREATE OR REPLACE do novo código da procedure tenderia a invalidar outros objetos dependentes também. O banco de dados parece “congelar”, o DBA não pode realizar as tarefas de patch (substituir alguns procedimentos, pacotes, views, triggers, e assim por diante), e os usuários finais não podem realizar as suas tarefas. Eles acabaram bloqueando e travando-se mutuamente.
Isto tudo termina tudo com o Oracle Database 11g Release 2 e o Edition-Based Redefinition, que permite aos DBAs e usuários finais acessar mais de uma ocorrência de uma stored procedure, trigger, view, e outros objetos e, portanto, isolar as mudanças em um esquema. Começando com o Oracle Database 11g Release 2, um único esquema pode agora ter duas ou mais ocorrências (vamos pensar em “versões”) de um stored procedure (função, trigger, e assim por diante) ou uma view ou de sinônimos e todos seus metadados relacionados, tais como GRANTS a esses objetos. (Estas duas ocorrências são independentes, eles coexistem, mas não interferem umas com as outras.) A “mágica” que permite isso é o novo objeto de edição (EDITION), que introduz um novo namespace transparente que permite mais de uma ocorrência ao mesmo tempo de uma stored procedure, trigger e assim por diante.
No passado, um objeto de esquema era referenciado com dois componentes: o owner do objeto e o nome. Isso impedira a existência de dois procedimentos armazenados como “P” em um único esquema. Ou seja, você poderia ter apenas um objeto referenciado por “OWNER.P”.
O objeto de edição no Oracle Database 11g Release 2 introduz uma terceira dimensão no esquema de resolução de nomes: todos os objetos são referenciados pela edição da sessão, o owner do objeto e o nome do objeto. Cada banco de dados tem pelo menos uma edição a ela associados, e a base de dados tem sempre uma edição padrão. Quando você cria uma sessão no Oracle Database 11g Release 2, a sua sessão terá um atributo associado a ela que indica a edição que sua sessão estará usando (por padrão, esta será a edição padrão do banco de dados). Usando ALTER SESSION, você pode especificar qualquer edição para a qual tiver sido concedido o acesso em sua sessão.
Quando você invocar ou referenciar objetos no Oracle Database 11g Release 2, esses objetos são referenciado também com a edição fixada na sua sessão. Isso significa que um administrador do aplicativo pode agora logar, alterar uma sessão para utilizar uma edição chamada VERSION2, por exemplo, e compilar o código para esta edição. O trabalho realizado pelo administrador da aplicação na edição VERSION2 é visível apenas em sessões usando a edição VERSION2. “VERSION2″ porque não é a edição padrão, ninguém mais vê essas mudanças (novas procedures, views, drop de pacotes, e assim por diante) a menos que a pessoa solicita especificamente (via ALTER SESSION) e tem o privilégio de usar e “ver” aquela edição. O administrador do aplicativo é capaz de criar ou substituir qualquer código sem concorrer com os outros que estão executando o código. Se o administrador do aplicativo precisa substituir 50 unidades de PL/SQL, essa pessoa pode fazê-lo em isolamento durante todo o tempo enquanto aplicação de produção continua rodando.
O exemplo a seguir demonstra este pequeno conceito. Vou começar como DBA, criando uma conta de demonstração e concedendo o mínimo de privilégios necessário:
SQL> create user demo 2 identified by demo; User created. SQL> grant create session, 2 create procedure 3 to demo; Grant succeeded.
Agora vou iniciar o processo que me permitirá criar mais de uma ocorrência de objetos do meu código na base de dados. Vou precisar de uma nova edição, a fim de fazer isso. O seguinte comando cria a nova edição:
SQL> create edition version2 2 as child of ora$base; Edition created.
Criei uma edição chamada VERSION2 no meu banco de dados, e ela começa sendo filha de ORA$BASE. Como mencionado acima, cada banco de dados tem pelo menos uma edição e cada banco de dados tem uma edição padrão. Por exemplo, todo Oracle Database 11g Release 2 vai ter uma edição padrão chamado ORA$BASE. Como filha de ORA$BASE, minha edição VERSION2 começa a vida como uma cópia completa da edição padrão ORA$BASE. Tudo que está valendo em ORA$BASE também está em VERSION2.
É importante notar, contudo, que esta VERSION2 é uma cópia virtual. A instrução CREATE EDITION não copia fisicamente cada objeto da ORA$BASE. Pelo contrário, VERSION2 aponta para os objetos ORA$BASE, e não vai começar a usar espaço no dicionário até que eu modifique os objetos no contexto da edição VERSION2.
Então, agora eu vou instalar a versão 1 da minha aplicação na conta DEMO:
DEMO> create or replace 2 procedure my_procedure 3 as 4 begin 5 dbms_output.put_line 6 ( 'I am version 1.0' ); 7 end; 8 / Procedure created. DEMO> create or replace 2 procedure my_procedure2 3 as 4 begin 5 my_procedure; 6 end; 7 / Procedure created.
Até agora muito simples, e quando eu executo essa “aplicação” eu vejo o seguinte:
DEMO> exec my_procedure2 I am version 1.0 PL/SQL procedure successfully completed.
Agora, vamos supor que este código esteja executando em produção por um tempo e eu descubro um bug, algo que precise reparar na stored procedure. No passado, eu precisaria que o usuário parasse de rodar, a fim de instalar o novo código.
Agora, no entanto, eu posso levantar a mudança no banco de dados enquanto o banco está funcionando, e os usuários estão executando o meu código com a edição padrão (ORA$BASE). Primeiro, como o DBA, eu preciso permitir que a conta DEMO use edições, e então eu preciso permitir que a conta DEMO veja e use a edição VERSION2. Além disso, para esta demonstração, vou deixar que a conta SCOTT veja e use VERSION2:
SQL> alter user demo 2 enable editions; User altered. SQL> grant use 2 on edition version2 3 to demo; Grant succeeded. SQL> grant use 2 on edition version2 3 to scott; Grant succeeded.
A instrução ALTER USER permite que a conta DEMO use edições dos códigos. Sem este GRANT, a conta DEMO seria capaz de ter apenas de ter uma cópia do código em vigor, em determinado momento, assim como na versão 7.0 até a versão 11.1 do Oracle Database. A instrução GRANT USE em seguida, permite que a conta DEMO e SCOTT vejam a edição VERSION2. Como a conta DEMO é habilitada para edição, ela será capaz de modificar a edição VERSION2 assim como alterar implementação de vários objetos, nesta edição, sem afetar outras edições. A conta SCOTT será capaz de usar apenas a edição deste VERSION2 – para definir a sua edição atual, na sua sessão de VERSION2 e ver os objetos como eles existem naquela edição.
Agora eu vou “patchear” a minha aplicação. Logando novamente com a conta DEMO, vou ver primeiro o que eu tenho no local após alterar a minha sessão de usar a edição VERSION2, como mostrado na Listagem 1.
Listagem de código 1: Definindo a edição VERSION2 e selecionando procedures
DEMO> alter session 2 set edition = version2; Session altered. DEMO> select object_name, 2 object_type, 3 status, 4 edition_name 5 from user_objects; OBJECT_NAME OBJECT_TYPE STATUS EDITION_NAME ------------- ----------- ------ ------------ MY_PROCEDURE2 PROCEDURE VALID ORA$BASE MY_PROCEDURE PROCEDURE VALID ORA$BASE
Então, agora, na edição VERSION2, eu tenho ambas unidades de PL/SQL (MY_PROCEDURE e MY_PROCEDURE2), mas como denota a coluna EDITION_NAME, eles são “herdadas” da ORA$BASE. A edição VERSION2 está apontando para a cópia em ORA$BASE, mas não é uma cópia física do código.
Digamos que eu tenha que corrigir dois bugs. Primeiro, eu tenho um bug na implementação de MY_PROCEDURE, e eu vou substituir esse código. Em segundo lugar, eu perdi um GRANT, quando estava fazendo deploy do meu aplicativo, o usuário SCOTT era pra ter o privilégio EXECUTE MY_PROCEDURE2, mas de alguma forma isso não aconteceu quando eu instalei a última aplicação. Eu vou começar atualizando o código:
DEMO> create or replace 2 procedure my_procedure 3 as 4 begin 5 dbms_output.put_line 6 ( 'I am version 2.0' ); 7 end; 8 / Procedure created. DEMO> select object_name, 2 edition_name 3 from user_objects; OBJECT_NAME EDITION_NAME ------------- ------------ MY_PROCEDURE2 ORA$BASE MY_PROCEDURE VERSION2
Como você pode ver, eu ainda tenho apenas dois objetos, mas existem três objetos físicos lá, como você verá em seguida. Tenho MY_PROCEDURE2, que é herdado ORA$BASE, e eu tenho MY_PROCEDURE, que agora existe fisicamente na edição VERSION2. Isso é chamado de colocar em prática o código quando eu tenho uma cópia física na edição, eu atualizei o código naquela edição.
Usando um novo conjunto de views pra ver em todas as edições e final em _AE – Eu posso ver todo o estado do meu esquema DEMO. Eu consulto a view USER_OBJECTS_AE para OBJECT_NAME e EDITION_NAME:
DEMO> select object_name, 2 edition_name 3 from user_objects_AE; OBJECT_NAME EDITION_NAME ------------- ------------ MY_PROCEDURE ORA$BASE MY_PROCEDURE2 ORA$BASE MY_PROCEDURE VERSION2
Olhando para as diferentes edições, você pode ver que eu atualizei duas cópias físicas de MY_PROCEDURE agora: uma na edição padrão ORA$BASE e uma na nova edição VERSION2 que estou trabalhando. Agora vou aplicar o grant de EXECUTE para SCOTT:
DEMO> grant execute 2 on my_procedure2 3 to scott; Grant succeeded. DEMO> select object_name, 2 edition_name 3 from user_objects; OBJECT_NAME EDITION_NAME ------------- ------------ MY_PROCEDURE2 VERSION2 MY_PROCEDURE VERSION2 DEMO> select object_name, 2 edition_name 3 from user_objects_AE; OBJECT_NAME EDITION_NAME ------------- ------------ MY_PROCEDURE2 ORA$BASE MY_PROCEDURE ORA$BASE MY_PROCEDURE2 VERSION2 MY_PROCEDURE VERSION2
Se você olhar para USER_OBJECTS, verá que eu tenho as duas procedures, mas ambas já foram atualizadas na edição VERSION2. Ao conceder o grant de EXECUTE nas procedures MY_PROCEDURE2 para SCOTT, eu fiz uma versão física da stored procedure aparecer na edição VERSION2, e eu apliquei o grant para que a edição em isolamento, sem encontrar quaisquer problemas de concorrência (problemas de bloqueios / lock porque alguém estava rodando a procedure). Olhando a USER_OBJECTS_AE, você pode ver que há agora quatro objetos físicos, dois em cada edição.
Agora, quando eu executo a procedure MY_PROCEDURE2 na edição VERSION2, eu vejo
DEMO> SELECT SYS_CONTEXT
2 ('userenv',
3 'current_edition_name') sc
4 FROM DUAL;
SC
----------------------
VERSION2
DEMO> exec my_procedure2
I am version 2.0
PL/SQL procedure successfully completed.
A versão 2.0 do código é executada.
Agora, simplesmente por conectar e depois usar o banco com edição padrão (ainda ORA$BASE), iremos ver
DEMO> connect demo/demo
Connected.
DEMO> SELECT SYS_CONTEXT
2 ('userenv',
3 'current_edition_name') sc
4 FROM DUAL;
SC
-----------------------
ORA$BASE
DEMO> exec my_procedure2
I am version 1.0
PL/SQL procedure successfully completed.
A versão 1.0 do código ainda está lá, e por padrão, ele será executado.
Além disso, para ver o efeito do privilégio EXECUTE que eu concedi ao SCOTT, eu posso conectar como SCOTT e tentar executar o procedimento armazenado MY_PROCEDURE2 na edição padrão e a edição VERSION2, como mostrado na Listagem 2.
Listagem de código 2: Executando my_procedure2 em edições atuais e na VERSION2
DEMO> connect scott/tiger
Connected.
SCOTT> SELECT SYS_CONTEXT
2 ('userenv',
3 'current_edition_name') sc
4 FROM DUAL;
SC
-----------------------
ORA$BASE
SCOTT> exec demo.my_procedure2
BEGIN demo.my_procedure2; END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00201: identifier 'DEMO.MY_PROCEDURE2' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SCOTT> alter session
2 set edition = version2;
Session altered.
SCOTT> exec demo.my_procedure2
I am version 2.0
PL/SQL procedure successfully completed.
Como você pode ver, quando SCOTT está usando a edição ORA$BASE, ele não pode ver ou executar a stored procedure MY_PROCEDURE2. No entanto, na edição VERSION2 o usuário SCOTT pode ver e executar esse procedimento, por isso, quando a versão 2.0 do aplicativo entra em produção, SCOTT terá a capacidade de executar esse procedimento por padrão.
Neste ponto, estou pronto para liberar este código para a produção para ser utilizado pela comunidade geral. Um único, simples ALTER DATABASE feito pelo DBA define a edição atual do banco de dados para VERSION2, e esse código se torna imediatamente acessível.
Gostaria de salientar que esta é apenas a ponta do iceberg. Aqui eu tive que fazer operações relativamente comums: substituir algumas unidades PL/SQL existentes e mudar GRANTS em alguns objetos. Eu não tomei toda a aplicação da versão 1.0 para a versão 2.0, porque isso implicaria mudar tabelas e outros objetos que não são “editáveis”. Então, o que esta coluna discutiu até agora é uma necessidade muito comum de aplicar correções em um sistema, em que você precise aplicar alterações e mudanças de código e privilégio, mas não alterações físicas, como alterações de esquema como adicionar colunas, acrescentar índices ou alterar tabelas. Estarei abordando a forma de realizar essas tarefas na próxima coluna.
Até então, veja o Capítulo 19 “Oracle Database Advanced Application Developer’s Guide 11g Release 2 (11.2)” encontrado em www.bit.ly/1m2n0J.
Esta é uma tradução literal do artigo escrito por Tom Kyte na Oracle Magazine de Janeiro/2010 por glufke.net.
Comente AQUI
Tags: DBA, Edition-Based Redefinition, Funções, Oracle 11g
