2015-04-28 3 views
5

Ich hatte ein Performance-Problem durch eine falsche XPath verursacht ('@' fehlt in Attribut Prädikat) in einer Abfrage wie folgt aus:Verständnis erklären Plan durch xmltype

wählen ExtractValue (Feld, ‚// item [attr =“ Wert "] ') aus Tabelle, wo field1 =: 1;

Ich erwartete eine Ausnahme aber scheint, dass Oracle diesen bestimmten XPath akzeptieren, hat eine Bedeutung?

Ich habe versucht, einen Plan gegen diese Abfrage auszuführen, aber das Ergebnis ist ziemlich seltsam, kann jemand mir helfen, es zu verstehen?

verwenden ich diesen Code der Umwelt

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 | 
------------------------------------------------------------------------------------------------ 
*/ 

Im ersten erkläre es eine ‚verschachtelte Schleifen‘ ist (Zeile 2) mit 667 T Kardinalität zu reproduzieren, die in dem zweiten verschwunden. Wenn Sie mehr Datensätze in dieselbe Tabelle einfügen und eine neue EXPLAIN-Ebene (ohne '@') ausführen, ist dieser Wert immer 667K.

Was bedeutet dieser Wert?

Antwort

1

Ich erwartete eine Ausnahme aber scheint, dass Oracle diesen bestimmten XPath akzeptieren, hat eine Bedeutung?

Nun, ja. Der xpath /root/g[key="G"] ruft an sich den Knoten ab, der ein Kind mit dem Tag "key" und dem Wert "G" hat. Also, auch wenn die ExtractValue scheitern würde (mehr als ein Knoten zurückgegeben), das funktionieren würde:

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; 

Es gibt <g key="G"><key>G</key>Ggg</g>

Die hohen Kosten in dieser Art der Suche gerechtfertigt sein könnte, weil Attribute wahrscheinlich optimierter und durchsuchbarer als andere Arten von Unterknoten (es kann genügen zu sagen, dass es für jeden Tag nur einen mit einem bestimmten Namen geben kann, während Tags mehrfach wiederholt werden können).