2014-12-09 21 views
6

Abbiamo bisogno di implementare una riscrittura delle query con una variabile bind perché non abbiamo la possibilità di modificare il codice sorgente dell'applicazione web. Esempio:Come utilizzare Oracle DBMS_ADVANCED_REWRITE con la variabile bind?

BEGIN 
    SYS.DBMS_ADVANCED_REWRITE.declare_rewrite_equivalence (
    name    => 'test_rewrite2', 
    source_stmt  => 'select COUNT(*) from ViewX where columnA = :1', 
    destination_stmt => 'select COUNT(*) from ViewY where columnA = :1', 
    validate   => FALSE, 
    rewrite_mode  => 'recursive');  
END; 

Il comando sopra si tradurrà in errore perché c'è una variabile di legatura:

30353. 00000 - "expression not supported for query rewrite" 
*Cause: The SELECT clause referenced UID, USER, ROWNUM, SYSDATE, 
      CURRENT_TIMESTAMP, MAXVALUE, a sequence number, a bind variable, 
      correlation variable, a set result, a trigger return variable, a 
      parallel table queue column, collection iterator, a non-deterministic 
      date format token RR, etc. 
*Action: Remove the offending expression or disable the REWRITE option on 
      the materialized view. 

sto leggendo here che c'è un lavoro in giro, ma non riesco proprio a trovare il documento ovunque online.

Potrebbe dirmi per favore qual è il lavoro?

risposta

1

Non è possibile specificare i parametri di collegamento, ma dovrebbe già funzionare come si desidera. La chiave è il parametro recursive passato come mode. La modalità recursive e general intercetterà tutte le istruzioni che coinvolgono la tabella (o la vista), ignorando il filtro e trasformandole nella destinazione della seconda tabella (o vista), adattando la condizione del filtro dall'istruzione originale. (Se tu avessi definito come TEXT_MATCH, avrebbe verificato la presenza dello stesso filtro nella dichiarazione originale e di destinazione al fine di innescare la trasformazione.)

Nell'esempio sottostante si può vedere che, anche se noi don Definire una qualsiasi condizione di associazione, il filtro id = 2 viene applicato senza nervature; in altre parole è in realtà trasformando il SELECT * FROM A1 where id = 2 in SELECT * FROM A2 where id = 2

set LINESIZE 300 

drop table A1; 
drop view A2; 
drop index A1_IDX; 
EXEC SYS.DBMS_ADVANCED_REWRITE.drop_rewrite_equivalence (name => 'test_rewrite'); 

create table A1 (id number, name varchar2(20)); 

insert into A1 values(1, 'hello world'); 
insert into A1 values(2, 'hola mundo'); 

create index A1_IDX on A1(id); 

select * from A1; 

ALTER SESSION SET QUERY_REWRITE_INTEGRITY = TRUSTED; 

CREATE OR REPLACE VIEW A2 AS 
SELECT id, 
     INITCAP(name) AS name 
FROM A1 
ORDER BY id desc; 


BEGIN 
    SYS.DBMS_ADVANCED_REWRITE.declare_rewrite_equivalence (
    name    => 'test_rewrite', 
    source_stmt  => 'SELECT * FROM A1', 
    destination_stmt => 'SELECT * FROM A2', 
    validate   => FALSE, 
    rewrite_mode  => 'recursive'); 
END; 
/


select * from A1; 

     ID NAME    
---------- -------------------- 
     2 Hola Mundo   
     1 Hello World   




select * from A1 where id = 2; 


     ID NAME    
---------- -------------------- 
     2 Hola Mundo  


explain plan for 
select * from A1 where id = 2; 

select * from table(dbms_xplan.display); 


PLAN_TABLE_OUTPUT                                                                       
---------------------------------------------------------------------------------------- 
Plan hash value: 1034670462                                                                     

----------------------------------------------------------------------------------------                                                      
| Id | Operation      | Name | Rows | Bytes | Cost (%CPU)| Time  |                                                      
----------------------------------------------------------------------------------------                                                      
| 0 | SELECT STATEMENT    |  |  1 | 25 |  2 (0)| 00:00:01 |                                                      
| 1 | VIEW       | A2  |  1 | 25 |  2 (0)| 00:00:01 |                                                      
| 2 | TABLE ACCESS BY INDEX ROWID | A1  |  1 | 25 |  2 (0)| 00:00:01 |                                                      
|* 3 | INDEX RANGE SCAN DESCENDING| A1_IDX |  1 |  |  1 (0)| 00:00:01 |                                                      
----------------------------------------------------------------------------------------                                                      


PLAN_TABLE_OUTPUT                                                                       
--------------------------------------------------- 
Predicate Information (identified by operation id):                                                               
---------------------------------------------------                                                               

    3 - access("ID"=2)                                                                      

Note                                                                           
-----                                                                          
    - dynamic sampling used for this statement (level=2)                                                              
    - automatic DOP: Computed Degree of Parallelism is 1 because of parallel threshold                                                      

20 rows selected 

Come si può vedere

  1. il motore è in modo trasparente applicando la trasformazione e restituendo il risultato filtrato
  2. in cima a quello, la trasformazione sul filtro applicato. Il filtro viene "inserito" correttamente nella tabella di origine per estrarre i valori da A1. Non estrae ciecamente tutti i valori da A2 e quindi applica il filtro, quindi la performance viene preservata.