Oracle 在 IN 子句中使用子查询降低性能

Posted

技术标签:

【中文标题】Oracle 在 IN 子句中使用子查询降低性能【英文标题】:Oracle slow performance using subquery inside IN clause 【发布时间】:2016-02-22 15:39:08 【问题描述】:

我有这样的查询:

SELECT
  xmlelement("objects",
    xmlagg(
        xmlelement("object",
          xmlelement("accountId", ACCOUNTS.accountId),
          xmlelement("address", ACCOUNTS.ADDRESS)
      )
    )
    INTO obj_info_xml
    FROM 
      ACCOUNTS
    WHERE account_code IN (SELECT EXTRACTVALUE(VALUE(accountCodes), '/accountCode/text()') as accountCode
                 FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//accountCodes/accountCode'))) accountCodes); 

当我在IN 子句中硬编码值时,查询执行得很快,但是当我使用子查询从 xml 中选择时,我无法获得结果,因为它执行得非常慢。你有什么建议吗?

【问题讨论】:

一些建议...有些人发誓用 EXISTS 替换 IN 将提供性能优势,但您将获得多少改进是值得怀疑的 - 仍然很容易尝试更改。但是,我认为可能更有帮助的是对子查询使用子查询分解(使用 WITH 语句)。然后解析器将决定是否要将您的查询视为内联视图,或者是否要创建一个临时表来存储值。无论哪种方式,您都应该看到性能提升。在此处阅读有关子查询分解的信息:oracle-base.com/articles/misc/with-clause 当 RDBMS 被用作 XML 而不是 RDBMS 的数据存储时会发生这种情况。 不确定您使用的是哪个版本,但您是否使用XML indexes查看过。如果 XPATH 查找是瓶颈,这应该有助于加快速度。 我的直觉是放弃 xmlsequence,提取和提取值,转而使用 xmltable。但是,如果没有示例数据和您的帐户表的 ddl,您将很难为您提供帮助。请更新您的问题以包含额外信息。 Dank 你能提供一些例子,我如何用 WITH 子句更改 IN 子句,因为我不知道。 【参考方案1】:

假设 x 是一个 PL/SQL 变量,其中包含您的帐户代码列表,这样的事情应该会加快速度:

select xmlelement("objects",
                  xmlagg(xmlelement("object",
                                    xmlelement("accountId", accounts.accountid),
                                    xmlelement("address", accounts.address))
                         )
                 ) account_xml
into   obj_info_xml
from   accounts a
       inner join xmltable('//accountCodes/accountCode'
                           passing x
                           columns account_code varchar2(30) path '.') xdata  -- amend datatype as appropriate
         on a.account_code = xdata.account_code;

注意由于缺乏样本数据,未经测试。


好的,下面给你什么?

select xmlelement("objects",
                  xmlagg(xmlelement("object",
                                    xmlelement("accountId", accounts.accountid),
                                    xmlelement("address", accounts.address))
                         )
                 ) account_xml
into   obj_info_xml
from   accounts a
where  a.account_code in (select /*+ dynamic_sampling(xdata 10) */ 
                                 account_code
                          from   xmltable('//accountCodes/accountCode'
                                          passing x
                                          columns account_code varchar2(30) path '.') xdata); -- amend datatype as appropriate

另一个建议是将/*+ dynamic_sampling(xdata 10) */ 替换为/* cardinality(xdata <roughly expected number of rows>) */(当然,用相关号码覆盖)。

另外,您能否编辑您的问题以提供带有和不带有硬编码变量的查询的执行计划?

【讨论】:

感谢您的建议,但这也和我原来的查询一样慢 我已经用一些可能有用的建议更新了我的答案。

以上是关于Oracle 在 IN 子句中使用子查询降低性能的主要内容,如果未能解决你的问题,请参考以下文章

删除查询中包含大表的 IN 子句中的子查询性能

Oracle In(匹配)子句

Oracle In(匹配)子句

子查询(嵌套子查询)

在SQL Server中为什么不建议使用Not In子查询

Hibernate:在子选择查询中使用 IN 子句时出现错误