2015-04-28 69 views
5

解釋計劃我造成了錯誤的XPath性能問題(「@」的屬性謂語缺失)在這樣的查詢:瞭解通過的XMLType

選擇extractValue一起(場,「//商品[ATTR =」 value']')from table where field1 =:1;

我預料到一個例外,但似乎Oracle接受這個特殊的xpath, 有意思嗎?

我試圖對該查詢執行解釋計劃,但結果很奇怪,有人可以幫助我理解它?

我用這個代碼重現環境

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

在第一解釋是有「嵌套循環」與在第二個消失基數667K(行2)。 在同一個表格中插入更多記錄並執行新的解釋(不包含'@'),該值始終爲667K。

它代表什麼價值?

回答

1

我預料到一個異常,但似乎Oracle接受這個特定的xpath,有意義嗎?

嗯,是的。本身,xpath /root/g[key="G"]獲取具有標籤「key」和值「G」的子節點。所以,即使extractValue一起將失敗(返回多個節點),這會工作:

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; 

它返回<g key="G"><key>G</key>Ggg</g>

成本高,可以在這種搜索是合理的,因爲屬性可能比其他類型的子節點更加優化和可搜索(可以說每個標籤只能有一個具有特定名稱的標籤,而標籤可以重複多次)。