push_subq-控制子查询比外部连接先运行

http://bitirainy.itpub.net/post/330/1886

 

先子查询再做表连接比较有利,也就是说子查询本身代价不大,并且过滤掉很多记录,产生一个很小的结果集再做表连接,比较有利。


oracle  document:

The PUSH_SUBQ hint causes non-merged subqueries to be evaluated at the earliest possible step in the execution plan. Generally, subqueries that are not merged are executed as the last step in the execution plan. If the subquery is relatively inexpensive and reduces the number of rows significantly, then it improves performance to evaluate the subquery earlier.

反之就是 no_push_subq
The NO_PUSH_SUBQ hint causes non-merged subqueries to be evaluated as the last step in the execution plan. If the subquery is relatively expensive or does not reduce the number of rows significantly, then it improves performance to evaluate the subquery last.

我们通过查询的执行计划来看个例子

explain  plan  for  select   m.*
from  member m,offer  o
where  m.login_id = o.member_id
and exists (select 1 from  company where admin_member_id = m.login_id and id < 1000000)

SQL> @?/rdbms/admin/utlxplp;

--------------------------------------------------------------------
| Id  | Operation            |  Name       | Rows  | Bytes | Cost  |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |       |       |       |
|*  1 |  FILTER              |             |       |       |       |
|   2 |   MERGE JOIN         |             |       |       |       |
|   3 |    SORT JOIN         |             |       |       |       |
|   4 |     TABLE ACCESS FULL| OFFER       |       |       |       |
|*  5 |    SORT JOIN         |             |       |       |       |
|   6 |     TABLE ACCESS FULL| MEMBER      |       |       |       |
|*  7 |   TABLE ACCESS FULL  | COMPANY     |       |       |       |
--------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( EXISTS (SELECT 0 FROM "COMPANY" "COMPANY" WHERE
              "COMPANY"."ID"<1000000 AND "COMPANY"."ADMIN_MEMBER_ID"=:B1))
   5 - access("SYS_ALIAS_1"."LOGIN_ID"="O"."MEMBER_ID")
       filter("SYS_ALIAS_1"."LOGIN_ID"="O"."MEMBER_ID")
   7 - filter("COMPANY"."ID"<1000000 AND
              "COMPANY"."ADMIN_MEMBER_ID"=:B1)

Note: rule based optimization

25 rows selected.

这里可以看出是 member 和offer 先做表连接然后再和company表连接

加上提示看看

explain  plan  for select  /*+ push_subq */ m.*
from  member m,offer  o
where  m.login_id = o.member_id
and exists (select 1 from  company where admin_member_id = m.login_id and id < 1000000)

SQL> @?/rdbms/admin/utlxplp;

--------------------------------------------------------------------
| Id  | Operation            |  Name       | Rows  | Bytes | Cost  |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |   592 |   325K|   555 |
|*  1 |  HASH JOIN           |             |   592 |   325K|   555 |
|*  2 |   HASH JOIN          |             |   521 |   280K|   348 |
|   3 |    SORT UNIQUE       |             |       |       |       |
|*  4 |     TABLE ACCESS FULL| COMPANY     |   521 | 13025 |     2 |
|   5 |    TABLE ACCESS FULL | MEMBER      |  3466K|  1738M|     2 |
|   6 |   TABLE ACCESS FULL  | OFFER       |  3941K|    45M|     2 |
--------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("M"."LOGIN_ID"="O"."MEMBER_ID")
   2 - access("COMPANY"."ADMIN_MEMBER_ID"="M"."LOGIN_ID")
   4 - filter("COMPANY"."ID"<1000000)

Note: cpu costing is off

21 rows selected.

这里可以看出是member和company先连接,再和offer做表连接

再比如,我们假定以member为驱动表,和company先做nested  loop 比较有效,然后再和offer表连接,整个查询的效率最高,那我们可以控制执行计划按照我们的意愿进行。

explain plan  for  select  /*+ push_subq use_nl(m c) full(m) */ m.*
from  member m,offer  o
where  m.login_id = o.member_id
and exists (select 1 from  company c where c.admin_member_id = m.login_id and c.id < 1000000)

SQL> @?/rdbms/admin/utlxplp;

--------------------------------------------------------------------
| Id  | Operation            |  Name       | Rows  | Bytes | Cost  |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |   592 |   325K|  1262 |
|*  1 |  HASH JOIN           |             |   592 |   325K|  1262 |
|   2 |   NESTED LOOPS       |             |   521 |   280K|  1055 |
|   3 |    SORT UNIQUE       |             |       |       |       |
|*  4 |     TABLE ACCESS FULL| COMPANY     |   521 | 13025 |     2 |
|*  5 |    TABLE ACCESS FULL | MEMBER      |     1 |   526 |     2 |
|   6 |   TABLE ACCESS FULL  | OFFER       |  3941K|    45M|     2 |
--------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("M"."LOGIN_ID"="O"."MEMBER_ID")
   4 - filter("C"."ID"<1000000)
   5 - filter("C"."ADMIN_MEMBER_ID"="M"."LOGIN_ID")

Note: cpu costing is off

21 rows selected.

push_subq 为我们提供了一种控制执行计划的手段,如果我们不希望子查询先进行而是最后进行,自然可以使用no_push_subq。

总的来说,sql执行计划的调整,一定是建立在对表的索引、数据量、各阶段满足条件的返回结果的量上进行考量的。如果我熟悉应用和数据的情况下,我一般是通过hints来控制达到我所期望的执行计划,而很少去反复试验看哪种执行计划好。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8102208/viewspace-667562/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/8102208/viewspace-667562/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值