terça-feira, 27 de maio de 2014

12c – RMAN SQL Interface Improvements

No Oracle Database 12c, o utilitário RMAN sofreu diversas melhorias. E uma dessas melhorias é que agora você pode executar a maioria dos comandos SQL diretamente no RMAN, sem precisar especificar a palavra-chave SQL + comando.


Como era antes do 12c:


[oracle@mesene2 ~]$ rman target /

Recovery Manager: Release 11.2.0.4.0 - Production on Tue May 20 12:42:47 2014
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
connected to target database: ORCL (DBID=4216109927)

RMAN> SQL 'create table tabela_teste (coluna1 number)';
using target database control file instead of recovery catalog
sql statement: create table tabela_teste (coluna1 number)

RMAN> SQL 'insert into tabela_teste values (1)';
sql statement: insert into tabela_teste values (1)

RMAN> SQL 'select * from tabela_teste';
sql statement: select * from tabela_teste



No 12c:

[oracle@oracle01 ~]$ rman target /


Recovery Manager: Release 12.1.0.1.0 - Production on Tue May 20 12:34:13 2014

Copyright (c) 1982, 2013, Oracle and/or its affiliates. All rights reserved.

connected to target database: ORCL (DBID=1356220819)


RMAN> create table tabela_teste (coluna1 number);

using target database control file instead of recovery catalog

Statement processed



RMAN> insert into tabela_teste values (1);

Statement processed



O resultado do SELECT agora é mostrado na tela:


RMAN> select * from tabela_teste;


COLUNA1

----------

1



E também podemos utilizar o comando DESCRIBE:

RMAN> desc tabela_teste;


Name                                         Null? Type

----------------------------------------- -------- ----------------------------

COLUNA1                                            NUMBER





Abraço,


Alex Zaballa.

terça-feira, 13 de maio de 2014

12c – SQL Text Expansion

No Oracle Database 12c, foi introduzida uma nova funcionalidade, o SQL Text Expansion.

E na package DBMS_UTILITY, foi adicionada a procedure EXPAND_SQL_TEXT.


SQL> variable retorno clob


SQL> begin
dbms_utility.expand_sql_text( input_sql_text => 'select * from emp', output_sql_text => :retorno );
end;
/

PL/SQL procedure successfully completed.



SQL> print retorno



RETORNO

--------------------------------------------------------------------------------
SELECT "A1"."EMPNO" "EMPNO","A1"."ENAME" "ENAME","A1"."JOB" "JOB","A1"."MGR" "MG
R","A1"."HIREDATE" "HIREDATE","A1"."SAL" "SAL","A1"."COMM" "COMM","A1"."DEPTNO"
"DEPTNO" FROM "SCOTT"."EMP" "A1"


Vamos verificar o efeito com uma política de VPD:


SQL> SELECT count(*)

FROM emp e, dept d

WHERE d.deptno = e.deptno;



COUNT(*)

----------

14

Criando a política de VPD, para mostrar apenas os dados referentes ao departamento 30:


SQL> CREATE OR REPLACE FUNCTION hide_sal_comm ( v_schema IN VARCHAR2, v_objname IN VARCHAR2) RETURN VARCHAR2 AS

 con VARCHAR2 (200);


BEGIN

 con := 'deptno=30';

 RETURN (con);

END hide_sal_comm;

/
Function created.

SQL> BEGIN
DBMS_RLS.ADD_POLICY ( object_schema => 'scott', object_name => 'emp',
policy_name => 'hide_sal_policy', policy_function => 'hide_sal_comm');

END;

/

PL/SQL procedure successfully completed.


SQL> SELECT count(*)
FROM emp e, dept d

WHERE d.deptno = e.deptno;

COUNT(*)
----------

6


Verificando o SQL gerado:


SQL> variable retorno clob


SQL> begin
dbms_utility.expand_sql_text( input_sql_text => 'SELECT count(*) FROM emp e, dept d WHERE d.deptno = e.deptno', output_sql_text => :retorno );
end;
/

PL/SQL procedure successfully completed.



SQL> print retorno



RETORNO

--------------------------------------------------------------------------------
SELECT COUNT(*) "COUNT(*)" FROM (SELECT "A3"."EMPNO" "EMPNO","A3"."ENAME" "ENAM
E","A3"."JOB" "JOB","A3"."MGR" "MGR","A3"."HIREDATE" "HIREDATE","A3"."SAL" "SAL"
,"A3"."COMM" "COMM","A3"."DEPTNO" "DEPTNO" FROM "SCOTT"."EMP" "A3" WHERE "A3"."DEPTNO"=30) "A2","SCOTT"."DEPT" "A1" WHERE "A1"."DEPTNO"="A2"."DEPTNO"



Abraço,


Alex Zaballa.

sábado, 3 de maio de 2014

12c – PL/SQL From SQL

Antes do 12c, era necessário criar uma PL/SQL function/procedure (schema object) para utilizar em conjunto com um comando SQL e para isso era necessário ter privilégios de CREATE PROCEDURE.


Segue um exemplo retirado de uma apresentação do Tom Kyte:


SQL> create table t (x varchar2(5));


Table created.


SQL> insert into t values ( 'a' );

insert into t values ( '1' );

insert into t values ( null );


commit;

Como era antes do 12c:

SQL>create or replace
function is_number_old(x in varchar2) return varchar2 is
 Plsql_Num_Error exception;
 pragma exception_init(Plsql_Num_Error, -06502);
begin
 if (To_Number(x) is NOT null) then
  return 'Y';
 else
  return '';
  end if;
exception
 when Plsql_Num_Error then
  return 'N';
end;
/

Function created.


SQL> select rownum, x,
is_number_old(x) is_num
from t;

ROWNUM     X     IS_NUM

---------- ----- --------------------

1          a     N
2          1     Y
3

Trace após adicionar 110.000 registros na tabela, para comparar os tempos:





Como fica no 12c:

with
function Is_Number (x in varchar2) return varchar2 is
 Plsql_Num_Error exception;
 pragma exception_init(Plsql_Num_Error, -06502);
begin
 if (To_Number(x) is NOT null) then
   return 'Y';
 else
   return '';
 end if;
exception
 when Plsql_Num_Error then
  return 'N';
end Is_Number;

select rownum, x, is_number(x) is_num from t;


ROWNUM     X     IS_NUM
---------- ----- --------------------
1          a     N
2          1     Y
3






Podemos verificar uma diminuição significativa no tempo e cpu.


Abraço,


Alex Zaballa.

segunda-feira, 28 de abril de 2014

domingo, 27 de abril de 2014

12c - Statistics During Loads

No Oracle Database 12c, foi introduzida uma nova feature, Online Statistics Gathering for Bulk Loads.

O banco de dados irá coletar estatísticas automaticamente das tabelas durante os seguintes tipos de operações bulk load:

  • CREATE TABLE AS SELECT

  • INSERT INTO ... SELECT into an empty table using a direct path insert

Por padrão, parallel inserts usam direct path insert. Podemos forçar o direct path insert usando o hint  / * + APPEND * /.

Lembrando que ao coletar as estatísticas, o banco de dados não irá gerar histograms e nem coletar estatísticas para índices existentes. Para isso é necessário utilizar o DBMS_STATS.

Para a criação de índices, desde a versão 10G o Oracle automaticamente coleta as estatísticas do índice após a sua criação.

Para voltar a ter o comportamento anterior à release 12c e não coletar as estatísticas, podemos utilizar o hint NO_GATHER_OPTIMIZER_STATISTICS.




SQL> create table tabela_teste
(
coluna1 number,
coluna2 number
);
Table created.

SQL> begin
for i in 1..1000
loop
insert into tabela_teste values(i, i);
end loop;

commit;
end;
/
PL/SQL procedure successfully completed.

SQL> select count(*) from tabela_teste;
COUNT(*)
----------
1000


Podemos verificar que não existem estatísticas, pois foi um insert normal:

SQL> select table_name, num_rows, last_analyzed from user_tables where table_name='TABELA_TESTE';

TABLE_NAME                     NUM_ROWS   LAST_ANALYZED
------------------------------ ---------- -------------
TABELA_TESTE


Agora utilizando CTAS:

SQL> create table tabela_teste2 as select * from tabela_teste;
Table created.

SQL> select table_name, num_rows, last_analyzed from user_tables where table_name='TABELA_TESTE2';

TABLE_NAME                     NUM_ROWS   LAST_ANALYZED
------------------------------ ---------- -------------
TABELA_TESTE2                  1000       16-APR-14




Utilizando direct path insert:

SQL> create table tabela_teste3
(
  coluna1 number,
  coluna2 number
);
Table created.
 
SQL> insert /*+ APPEND */ into tabela_teste3 select object_id,object_id from user_objects where rownum < 30;
25 rows created.
 
SQL> select table_name, num_rows, last_analyzed from user_tables where table_name='TABELA_TESTE3';
 
TABLE_NAME                           NUM_ROWS         LAST_ANALYZED
------------------------------       ----------        -------------
TABELA_TESTE3                               25         16-APR-14 10:20:00
 
 

Quando a tabela não está vazia, as estatísticas não são atualizadas:

SQL> insert /*+ APPEND */ into tabela_teste3 select object_id,object_id from user_objects where rownum < 30;
25 rows created.

SQL> select table_name, num_rows, last_analyzed from user_tables where table_name='TABELA_TESTE3';

TABLE_NAME                     NUM_ROWS   LAST_ANALYZED
------------------------------ ---------- -------------
TABELA_TESTE3 25               16-APR-14  10:20:00


Verificando o plano de execução:

SQL> explain plan for
create table tabela_teste4 as select * from tabela_teste;

Explained.

SQL> select * from table(dbms_xplan.display(null, null, 'BASIC'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1183779688

------------------------------------------------------------------
| Id | Operation | Name |
------------------------------------------------------------------
| 0 | CREATE TABLE STATEMENT | |
| 1 | LOAD AS SELECT | TABELA_TESTE2 |
| 2 | OPTIMIZER STATISTICS GATHERING | |
| 3 | TABLE ACCESS FULL | TABELA_TESTE |
------------------------------------------------------------------

10 rows selected.



Obtendo informações sobre a coleta automática de estatísticas:

SQL> select table_name, column_name, num_distinct, notes from user_tab_col_statistics where table_name = ('TABELA_TESTE3');

TABLE_NAME           COLUMN_NAME          NUM_DISTINCT NOTES
-------------------- -------------------- ------------ ------------------------------
TABELA_TESTE3        COLUNA1              25            STATS_ON_LOAD
TABELA_TESTE3        COLUNA2              25            STATS_ON_LOAD


Para restrições na coleta automática, consultar a referência abaixo.


Referências:



Abraço,


Alex Zaballa

sábado, 19 de abril de 2014

12c - Last Successful Login Time in SQL*Plus

No Oracle Database 12c, foi introduzida uma nova funcionalidade no utilitário SQL*Plus, o Last Successful Login Time in SQL*Plus.

SQL*Plus do Oracle Database 12c adicionou uma informação na tela login, agora por default, é mostrada a última data e hora de login do usuário.


[oracle@oracle01]$ sqlplus scott/tiger
 
SQL*Plus: Release 12.1.0.1.0 Production on Thu Mar 27 16:23:55 2014
 
Copyright (c) 1982, 2013, Oracle.  All rights reserved.
 
Last Successful login time: Wed Mar 26 2014 16:02:23 +01:00
 
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Advanced Analytics
and Real Application Testing options
 

Essa informação também pode ser obtida na view DBA_USERS:

SQL> select username,last_login
from dba_users
where username = 'SCOTT';

USERNAME        LAST_LOGIN
--------------- -------------------------
SCOTT           27.03.2014 16:23:56




Para inibir isso, basta utilizar a opção nologintime:

[oracle@oracle01 tmp]$ sqlplus -nologintime scott/tiger

SQL*Plus: Release 12.1.0.1.0 Production on Thu Mar 27 16:26:40 2014

Copyright (c) 1982, 2013, Oracle. All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Advanced Analytics
and Real Application Testing options

SQL>



Referências:


Abraço

Alex Zaballa