2015-04-28 8 views
5

Ho avuto un problema di prestazioni causato da un XPath sbagliata ('@' manca in attributo predicato) in una query come questa:Capire spiegare piano attraverso XMLType

selezionare extractvalue (campo, '// voce [attr =" valore "] ') dalla tabella dove campo1 =: 1;

Mi aspettavo un'eccezione ma sembra che Oracle accetti questo particolare xpath, ha un significato?

Ho cercato di eseguire un piano di spiegazioni contro quella query ma il risultato è piuttosto strano, qualcuno può aiutarmi a capirlo?

Ho usato questo codice per riprodurre l'ambiente

SELECT * FROM V$VERSION; 
/* 
Oracle Database 11g Release 11.2.0.3.0 - 64bit Production 
PL/SQL Release 11.2.0.3.0 - Production 
"CORE 11.2.0.3.0 Production" 
TNS for Linux: Version 11.2.0.3.0 - Production 
NLSRTL Version 11.2.0.3.0 - Production 
*/ 

create table TMP_TEST_XML(
    id number, 
content_xml xmltype 
); 
/
create unique index IDX_TMP_TEST_XML on TMP_TEST_XML(id); 
/
declare 
    xml xmltype := xmltype('<root> 
    <a key="A">Aaa</a> 
    <b key="B">Bbb</b> 
    <c key="C">Ccc</c> 
    <d key="D">Ddd</d> 
    <e key="E">Eee</e> 
    <f key="F">Fff</f> 
    <g key="G">Ggg</g> 
    <h key="H">Hhh</h> 
    <i key="I">Iii</i> 
    <l key="L">Lll</l> 
</root>'); 
begin 

    for idx in 1..10000 
    loop 
    insert into TMP_TEST_XML values (idx, xml); 
    end loop; 

    commit; 

end; 
/
--explain plan xpath without '@' (wrong) 
EXPLAIN PLAN SET statement_id = 'planXml1' FOR 
select extractvalue(content_xml, '/root/g[key="G"]') from TMP_TEST_XML where id between 120 and 130; 
/ 
select plan_table_output 
from table(dbms_xplan.display('plan_table',null,'advanced')); 
/
/* 
------------------------------------------------------------------------------------------------ 
| Id | Operation     | Name    | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT   |     | 24 | 48360 |  4 (0)| 00:00:01 | 
| 1 | SORT AGGREGATE    |     |  1 |  4 |   |   | 
| 2 | NESTED LOOPS SEMI   |     | 667K| 2606K| 223K (1)| 00:44:37 | 
| 3 | XPATH EVALUATION   |     |  |  |   |   | 
|* 4 | XPATH EVALUATION   |     |  |  |   |   | 
| 5 | TABLE ACCESS BY INDEX ROWID| TMP_TEST_XML  | 24 | 48360 |  4 (0)| 00:00:01 | 
|* 6 | INDEX RANGE SCAN   | IDX_TMP_TEST_XML | 43 |  |  2 (0)| 00:00:01 | 
------------------------------------------------------------------------------------------------ 
*/ 
/
-- explain plan xpath with '@' (correct) 
EXPLAIN PLAN SET statement_id = 'planXml1' FOR 
select extractvalue(content_xml, '/root/g[@key="G"]') from TMP_TEST_XML where id between 120 and 130; 
/
select plan_table_output 
from table(dbms_xplan.display('plan_table',null,'advanced')); 
/
/* 
------------------------------------------------------------------------------------------------ 
| Id | Operation     | Name    | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT   |     | 24 | 48360 |  4 (0)| 00:00:01 | 
| 1 | SORT AGGREGATE    |     |  1 |  4 |   |   | 
|* 2 | XPATH EVALUATION   |     |  |  |   |   | 
| 3 | TABLE ACCESS BY INDEX ROWID| TMP_TEST_XML  | 24 | 48360 |  4 (0)| 00:00:01 | 
|* 4 | INDEX RANGE SCAN   | IDX_TMP_TEST_XML | 43 |  |  2 (0)| 00:00:01 | 
------------------------------------------------------------------------------------------------ 
*/ 

Nella prima spiegare c'è un 'cicli nidificati' (riga 2) con 667K cardinalità scomparsa nella seconda. Inserendo più record nella stessa tabella ed eseguendo una nuova spiegazione semplice (senza '@') tale valore è sempre 667K.

Che cosa rappresenta quel valore?

risposta

1

Mi aspettavo un'eccezione ma sembra che Oracle accetti questo particolare xpath, ha un significato?

Bene, sì. Di per sé, xpath /root/g[key="G"] recupera il nodo che ha un figlio con tag "chiave" e valore "G". Così, anche se l'extractvalue fallirebbe (più di un nodo viene restituito), questo dovrebbe funzionare:

select extract(xmltype('<root> 
<a key="A">Aaa</a> 
<g key="G"><key>G</key>Ggg</g> 
<h key="H">Hhh</h></root>'),'/root/g[key="G"]').getStringVal() from dual; 

Riporta <g key="G"><key>G</key>Ggg</g>

L'alto costo potrebbe essere giustificato in questo tipo di ricerca, in quanto gli attributi sono probabilmente più ottimizzato e ricercabile rispetto ad altri tipi di sottonodi (basti dire che ce ne può essere uno solo con un nome particolare per ogni tag, mentre i tag possono essere ripetuti più volte).

Problemi correlati