如何在SELECT语句中优化XQUERY?

3

我是使用Oracle数据库的。我的一个表中有一列是XMLTYPE类型的。现在,问题是我需要提取那些具有特定根元素和另一个条件的记录的计数。假设存储的XML格式如下:

<ns1:Warehouse whNo="102" xmlns:ns1="xyz">
  <ns1:Building></ns1:Building>
</ns1:Warehouse>

"and"。
 <ns1:Warehouse whNo="102" xmlns:ns1="xyz">
  <ns1:Building>Owned</ns1:Building>
 </ns1:Warehouse>

还有其他根元素不是Warehouse的XML文件

现在,我需要获取那些满足以下条件的记录:

  1. 根元素为Warehouse
  2. Building元素为空

我编写了以下SQL查询语句:

select count(XMLQuery('declare namespace ns1="xyz.com";
                       for $i in /*      
                       where fn:local-name($i) eq "Warehouse"  
                       and fn:string-length($i/ns1:Building ) = 0
                       return <Test>{$i/ns1:Building}</Test>'
                       PASSING xml_response RETURNING CONTENT)) countOfWareHouses
 from test

这里,“test”是表的名称,“*xml_response*”是表“test”中XMLTYPE列的名称。

当记录较少时,此查询可以正常工作。我已经在表中测试了约500条记录,并且所需时间约为0.1秒。但是随着表中记录数量的增加,所需时间也会增加。当我将记录数量增加到5000时,所需时间为约11秒。对于一个存储了185000条记录的生产表来说,此查询永远无法完成。

请帮助我优化此查询或xquery。

编辑1:

我尝试使用以下内容:

select count(XMLQuery(
         'declare namespace ns1 = "xyz";
         for $i in /
         return /ns1:Warehouse[not(ns1:Building/text())]'
         PASSING xml_response RETURNING CONTENT))
from test

并且

 select count(XMLQuery(
         'declare namespace ns1 = "xyz";
         return /ns1:Warehouse[fn:string-length(ns1:Building)=0]'
         PASSING xml_response RETURNING CONTENT))
from test

但是这并没有起作用。

当我尝试运行它们时,它会要求绑定 Building 和 Warehouse 的值。


1
你的XQuery看起来太复杂了。我敢打赌在XQuery中可以数空元素。这个答案似乎解决了你遇到的问题,只是它计算的是非空元素。希望能帮到你! - user272735
2个回答

1

相比使用速度更快的谓词,你应该使用它们:

ns1:Warehouse[string-length(ns1:Building)=0]

嗨,Navin,感谢您的回复。但是,我尝试使用了这个。我不确定我是否使用正确。我已经通过编辑1编辑了原始问题。如果您可以检查并建议更改,那将非常有帮助。 - systemhalted

1
如果不必要,不要使用local-name(...)。节点测试可能会更快并启用索引使用。您还可以删除string-length(...)调用。
搜索<Warehouse/>元素,在其<Building/>节点下方没有文本节点。如果您还想扫描任意子节点(包括属性!),请使用node()而不是text()。如果您只想确保某个地方有文本,可能作为其他节点的子级,请使用ns1:Building//text(),例如在这种情况下:<ns1:Building><foo>bar</foo></ns1:Building>
这个简单的XPath表达式正在做你需要的事情:
/ns1:Warehouse[not(ns1:Building/text())]

如果您需要构建这些<Test/>元素,请使用。
for $warehouse in /ns1:Warehouse[not(ns1:Building/text())]
return <Test>{$warehouse/ns1:Building}</Test>

我希望这个内容能够成为您XQuery的真正替代品。

我刚意识到您只想知道数字,那么最好在XQuery中计数(不过我不能告诉您如何阅读单个结果):

count(/ns1:Warehouse[not(ns1:Building/text())])

嗨Jens,谢谢您的回复。然而,我尝试使用了这个。我不确定我是否使用正确。我已经用编辑1编辑了原始问题。如果您可以检查并建议更改,那将非常有帮助。 - systemhalted
1
我刚意识到你一直在构建自己的结果元素。我相应地更新了我的答案。顺便说一句,如果你收到一个(错误)消息,请始终复制“精确”的消息,包括错误号等,不要用自己的话重复它。 - Jens Erat
Jens,创建自己的结果元素并不是我想要的,因为我只需要一个计数。如果可以避免使用结果元素,那将是一个受欢迎的解决方案。 - systemhalted
1
使用我的上一个查询,它只返回数字。在“聪明”的XQuery实现中(所有相关的都应该是),不会有任何中间结果。它将返回单个数字。 - Jens Erat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接