XML 表上 PLSQL 查询的性能调整

问题描述 投票:0回答:1

我需要对 Oracle 数据库上的表执行一些查询。该表包含 XML 值。下面是我的 xml 结构示例:

<Parent>
  <ParentId>382010</ParentId>
  <LastUpd>2023-03-01T22:59:10.456241</LastUpd>
  <UserId>0</UserId>
  <attrn>xxx</attrn>
  <Child>
     <ChildId>1</ChildId>
    <Attribute1 ID="1873" D="1466 Description">1466</Attribute1>
    <Attribute2 ID="1234" D="QWERTY Description" E="503" ED="Error 503 Description">QWERTY</Attribute2>
    <Attribute3 ID="4921" D="Other Description">YourValue</Attribute3>
  </Child>
  <Child>
    <ChildId>2</ChildId>
    <Attribute1 ID="1296" D="Some Description">1234</Attribute1>
    <Attribute2 ID="1234" D="Some Different Description">ABC</Attribute2>
    <Attribute3 ID="4921" D="Other Description"  E="501" ED="Error 501 Description">MyValye</Attribute3>
  </Child>
</Parent>

我需要选择所有有错误的孩子属性,可以通过“E”属性来识别(例如孩子1中的属性2和孩子2中的属性3)。

我对这种 XML 查询不是很专家,经过一番尝试后,我最终构建了下面的查询:

SELECT EXTRACTVALUE (VALUE (X), '/Parent/UserId')  AS USER_ID
      ,EXTRACTVALUE (VALUE (X), '/Parent/ParentId')  AS PARENT_ID
      ,EXTRACTVALUE (VALUE (X), '/Parent/attrn')  AS PARENT_ATTR_N_COL_NAME
      ,EXTRACTVALUE (VALUE (I), '/Child/ChildId') AS ROW_NUM
      ,CASE
         WHEN EXISTSNODE (VALUE (E), '/Attribute1/@E') = 1 THEN ATTR_ONE_COL_NAME
         WHEN EXISTSNODE (VALUE (E), '/Attribute2/@E') = 1 THEN ATTR_TWO_COL_NAME
         WHEN EXISTSNODE (VALUE (E), '/Attribute3/@E') = 1 THEN ATTR_THREE_COL_NAME
        END AS FIELD
      ,EXTRACTVALUE (VALUE(E), '/*/text()') as VALUE
      ,EXTRACTVALUE (VALUE(E), '/*/@E') as ERROR_CODE
      ,EXTRACTVALUE (VALUE(E), '/*/@ED') as ERROR_DESC
  FROM XML_TABLE X
      ,TABLE (XMLSEQUENCE (EXTRACT (VALUE (X), '/Parent/Child')))  I
      ,TABLE (XMLSEQUENCE (EXTRACT (VALUE (I), '/Child/*'))) E
 WHERE     EXTRACTVALUE (VALUE (X), '/Parent/ParentId') = 382010
       AND EXISTSNODE (VALUE (E), '/*/@E') = 1';                                                                                      

当然,XML(然后是查询)实际上要大得多,我只是发布了一个简化的示例以使其更加综合。有时父节点包含数百个子节点,有时我需要查询数千个父节点,所以我想知道是否有一种方法可以优化上述查询并使其更快。

非常感谢:)


performance plsql query-optimization xmltable fine-tuning
1个回答
0
投票

考虑用更新且更强大的

EXTRACTVALUE
 替换已弃用的 
XMLTABLE
函数。使用
XMLTABLE
,所有解析都可以在一次查询中完成。然后,您可以使用该查询来执行 DML 操作,也可以循环遍历它以进行更多的过程控制。

下面的代码与您的结果并不完全匹配,但它足够接近,可以让您了解它是如何工作的。

select
    parent.user_id, parent.parent_id, parent.parent_attr_n_col_name,
    child.row_num, attribute.value, attribute.error_code, attribute.error_desc
from xmltest x,
xmltable
('/Parent' passing x.a columns
    user_id number path 'UserId',
    parent_id number path 'ParentId',
    parent_attr_n_col_name path 'attrn'
) parent,
xmltable
('/Parent/Child' passing x.a columns
    row_num number path 'ChildId'
) child,
xmltable
('/Parent/Child/*' passing x.a columns
    value varchar2(100) path 'text()',
    error_code varchar2(100) path '@E',
    error_desc varchar2(100) path '@ED'
) attribute
where parent_id = 382010
    and error_code is not null;

这是我用于测试代码的架构:

--drop table xmltest;

create table xmltest(a xmltype);

insert into xmltest values(xmltype('
<Parent>
  <ParentId>382010</ParentId>
  <LastUpd>2023-03-01T22:59:10.456241</LastUpd>
  <UserId>0</UserId>
  <attrn>xxx</attrn>
  <Child>
     <ChildId>1</ChildId>
    <Attribute1 ID="1873" D="1466 Description">1466</Attribute1>
    <Attribute2 ID="1234" D="QWERTY Description" E="503" ED="Error 503 Description">QWERTY</Attribute2>
    <Attribute3 ID="4921" D="Other Description">YourValue</Attribute3>
  </Child>
  <Child>
    <ChildId>2</ChildId>
    <Attribute1 ID="1296" D="Some Description">1234</Attribute1>
    <Attribute2 ID="1234" D="Some Different Description">ABC</Attribute2>
    <Attribute3 ID="4921" D="Other Description"  E="501" ED="Error 501 Description">MyValye</Attribute3>
  </Child>
</Parent>'));

这是您的查询,根据之前的架构进行了一些对我有用的更改。我不确定你的表是如何设置的 - 使用 REF 而不是值?

SELECT
      EXTRACTVALUE (X.a, '/Parent/UserId')  AS USER_ID
      ,EXTRACTVALUE (X.a, '/Parent/ParentId')  AS PARENT_ID
      ,EXTRACTVALUE (X.a, '/Parent/attrn')  AS PARENT_ATTR_N_COL_NAME
      ,EXTRACTVALUE (I.column_value, '/Child/ChildId') AS ROW_NUM
--      ,CASE
--         WHEN EXISTSNODE (E.column_value, '/Attribute1/@E') = 1 THEN ATTR_ONE_COL_NAME
--         WHEN EXISTSNODE (E.column_value, '/Attribute2/@E') = 1 THEN ATTR_TWO_COL_NAME
--         WHEN EXISTSNODE (E.column_value, '/Attribute3/@E') = 1 THEN ATTR_THREE_COL_NAME
--        END AS FIELD
      ,EXTRACTVALUE (E.column_value, '/*/text()') as VALUE
      ,EXTRACTVALUE (E.column_value, '/*/@E') as ERROR_CODE
      ,EXTRACTVALUE (E.column_value, '/*/@ED') as ERROR_DESC
  FROM xmltest X
      ,TABLE (XMLSEQUENCE (EXTRACT (X.a, '/Parent/Child')))  I
      ,TABLE (XMLSEQUENCE (EXTRACT (value(I), '/Child/*'))) E
 WHERE     EXTRACTVALUE (X.a, '/Parent/ParentId') = 382010
       AND EXISTSNODE (VALUE (E), '/*/@E') = '1';
© www.soinside.com 2019 - 2024. All rights reserved.