使用 Oracle PL/SQL XMLQUERY 和 XQuery 代替“EXTRACT(XML)”有什么优势

And*_*uze 6 xml oracle oracle11g oracle12c

我注意到 Oracle EXTRACT(XML) 函数在 Oracle 11g 中已弃用。

我曾经通过以下方法进行 XML 处理:

DECLARE
  TYPE xmltype_table IS TABLE OF xmltype INDEX BY PLS_INTEGER;
  vt_xml_tab xmltype_table;
  v_xml      xmltype;
BEGIN
  --Generate simple XML document to pretend we received it by some interface
  SELECT xmltype(dbms_xmlgen.getxml('select level, dbms_random.random rnd from dual connect by level<1000')) INTO v_xml FROM dual;

  --Get nodes
  SELECT VALUE(xm) xmlt BULK COLLECT INTO vt_xml_tab FROM TABLE(xmlsequence(v_xml.extract('/ROWSET/ROW/LEVEL'))) xm;

  --Do whatever processing I like
  FOR i IN 1..vt_xml_tab.count LOOP
    dbms_output.put_line(vt_xml_tab(i).extract('LEVEL/text()').getstringval());
  END LOOP;
END;
/
Run Code Online (Sandbox Code Playgroud)

由于 EXTRACT 已被弃用,Oracle 建议我应该使用 XMLQUERY: http://docs.oracle.com/cd/E18283_01/server.112/e17118/functions060.htm

我想重写我之前的处理如下:

DECLARE
  TYPE xmltype_table IS TABLE OF xmltype INDEX BY PLS_INTEGER;
  vt_xml_tab xmltype_table;
  v_xml      xmltype;
BEGIN
  --Generate simple XML document to pretend we received it by some interface
  SELECT xmltype(dbms_xmlgen.getxml('select level, dbms_random.random rnd from dual connect by level<1000'))
    INTO v_xml
    FROM dual;

  SELECT xmlquery('for $i in /ROWSET/ROW
      return $i/LEVEL' passing rowset_xml RETURNING content)
    INTO v_xml
    FROM (SELECT v_xml rowset_xml FROM dual);

  --Get nodes
  SELECT VALUE(xm) xmlt BULK COLLECT INTO vt_xml_tab FROM TABLE(xmlsequence(v_xml)) xm;

  --Do whatever processing I like
  FOR i IN 1 .. vt_xml_tab.count LOOP
    FOR x IN (SELECT extractvalue(vt_xml_tab(i), 'LEVEL') lvl FROM dual) LOOP
      dbms_output.put_line(x.lvl);
    END LOOP;
  END LOOP;
END;
/
Run Code Online (Sandbox Code Playgroud)

但事实证明,使用 XMLQUERY 速度明显慢(在我的机器上通过挂钟测量为 0.8 秒 vs 1.8 秒)。

有没有更好的方法不使用 EXTRACT 函数?

p3c*_*ing 0

BEGIN
    FOR rec IN (
        SELECT 
        t.lvl, t.rnd
        FROM  
        XMLTABLE(
            '/ROWSET/ROW' PASSING (
            SELECT XMLTYPE(DBMS_XMLGEN.GETXML('select level, dbms_random.random rnd from dual connect by level<1000'))
                FROM Dual
            )
            COLUMNS 
                lvl NUMBER path 'LEVEL',
                rnd NUMBER path 'RND'
        ) t
    )
    LOOP
        DBMS_OUTPUT.PUT_LINE(rec.lvl || ' ' || rec.rnd);
    END LOOP ;
END ;
/
Run Code Online (Sandbox Code Playgroud)