【问题标题】:Join query taking more time compared to query with sub-query与使用子查询的查询相比,加入查询需要更多时间
【发布时间】:2016-04-22 12:01:37
【问题描述】:

我有一个带有子查询的查询,它需要大约 10 分钟的时间来执行,所以我想使用 JOIN 编写相同的逻辑来更快地获得结果。但最终,与子查询相比,JOIN 查询花费的时间要多得多。

使用子查询

select count(distinct nrc_app_no) from nrc_doc_submit_tbl 
where ng_status='Uploaded' 
and (processed_by is null OR processed_by='XML1')
and nrc_app_no not in 
(
  select distinct nrc_app_no from nrc_doc_submit_tbl where ng_status='Parsed'
)
and 
(
   nrc_app_no not like '4%' and
   nrc_app_no not like '5%' and
   nrc_app_no not like '6%'
);

计划:

使用 JOIN 和 substr

select count(distinct a.nrc_app_no)
from 
   nrc_doc_submit_tbl a left join nrc_doc_submit_tbl b
on 
   a.nrc_app_no=b.nrc_app_no and b.ng_status='Parsed' and a.ng_status='Uploaded' 
   and (a.processed_by is null OR  a.processed_by='XML1')
where 
  b.nrc_app_no is null and substr(a.nrc_app_no,1,1) not in ('4','5','6');

计划

数据库:Oracle 11g

表格大小:1000 万行

我还附上了这两个查询的计划。

主键:NRC_APP_NO、FAMILY_MEMBER_ID、NRC_DOC_SUBMIT_ID

索引列表:

【问题讨论】:

  • 编辑您的问题并提供表格的布局,尤其是索引和主键。
  • @GordonLinoff ,我附上了索引列表,还提到了主键。

标签: sql oracle join


【解决方案1】:

您不需要使用自联接或相关子查询,因为您可以使用 analytic function 获得相同的功能(只需要一次表扫描):

SELECT COUNT( DISTINCT nrc_app_no )
FROM   (
  SELECT nrc_app_no,
         ng_status,
         processed_by,
         COUNT( CASE ng_status WHEN 'Parsed' THEN 1 END )
           OVER ( PARTITION BY nrc_app_no ) AS parsed_count
  FROM   nrc_doc_submit_tbl
)
WHERE  ng_status    = 'Uploaded'
AND    (processed_by is null OR processed_by='XML1')
AND    parsed_count = 0
AND    nrc_app_no   NOT LIKE '4%'
AND    nrc_app_no   NOT LIKE '5%'
AND    nrc_app_no   NOT LIKE '6%';

替代方案 - 不存在

返回两个表(或索引)扫描:

SELECT COUNT( DISTINCT nrc_app_no )
FROM   nrc_doc_submit_tbl a
WHERE  ng_status    = 'Uploaded'
AND    (processed_by is null OR processed_by='XML1')
AND    NOT EXISTS (
                    SELECT 'X'
                    FROM   nrc_doc_submit_tbl b
                    WHERE  a.nrc_app_no = b.nrc_app_no
                    AND    b.ng_status  = 'Parsed'
                  )
AND    nrc_app_no   NOT LIKE '4%'
AND    nrc_app_no   NOT LIKE '5%'
AND    nrc_app_no   NOT LIKE '6%';

【讨论】:

  • 感谢@MT0 的帮助
  • 当我是您的查询时,它会抛出一个错误,指出最后一行中的 nrc_app_no 标识符无效。 from 子句中的查询运行良好。甚至我在 from 子句中为查询使用了别名,但同样的错误再次出现。
  • @SagarJoon 已更新 - 缺少逗号
  • 您的查询所用时间是子查询所用时间的两倍。
  • @SagarJoon 添加了使用NOT EXISTS 而不是NOT IN 的替代方法
【解决方案2】:

你可以通过改变这个来加速第一个:

and nrc_app_no not in 
(
select distinct nrc_app_no from nrc_doc_submit_tbl where ng_status='Parsed' 
)

到这里:

and nrc_app_no in 
(
select nrc_app_no from nrc_doc_submit_tbl
minus
select nrc_app_no from nrc_doc_submit_tbl 
where ng_status='Parsed'
)

not in 很慢。

过滤函数结果也很慢。你有这个:

and substr(a.nrc_app_no,1,1) not in ('4','5','6')

使用第一个查询的语法可能会更好。

【讨论】:

  • 使用INMINUS 你不是在做额外的表扫描(或索引扫描)吗?这真的比使用NOT IN 快吗?您能否提供参考来支持性能声明,因为我想了解更多信息?
  • 感谢@Dan Bracuk 的帮助
  • @MT0,这种技术非常不直观,但它确实有效。我的参考是我得到的结果。我可以举一个例子,但再说一遍,你也可以。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-30
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多