楼主: rollingpig

[精华] 一次SQL Tuning引出来的not in , not exists 语句的N种写法

[复制链接]
论坛徽章:
44
青年奥林匹克运动会-自行车
日期:2014-09-12 22:37:432012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-02-13 15:12:09咸鸭蛋
日期:2012-01-08 14:47:322012新春纪念徽章
日期:2012-01-04 11:50:44ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15迷宫蛋
日期:2011-08-14 17:30:33双黄蛋
日期:2011-05-28 20:32:46紫蛋头
日期:2011-05-18 20:41:51现任管理团队成员
日期:2011-05-07 01:45:08
41#
发表于 2005-12-12 10:27 | 只看该作者
这些方法各有千秋啊!多谢楼主!个人比较倾向于outer jion + null condition,不过有时候别的方法可能更快,只能试着来啦。

使用道具 举报

回复
论坛徽章:
81
青年奥林匹克运动会-马术
日期:2014-09-10 21:37:07奥运会纪念徽章:跳水
日期:2012-09-22 18:27:58奥运会纪念徽章:现代五项
日期:2012-09-07 17:33:44奥运会纪念徽章:铁人三项
日期:2012-06-15 21:27:24版主1段
日期:2012-05-15 15:24:11蜘蛛蛋
日期:2012-05-14 10:50:40灰彻蛋
日期:2012-03-06 19:24:222012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-02-13 15:12:09ITPUB 11周年纪念徽章
日期:2012-10-09 18:05:37
42#
发表于 2005-12-16 23:49 | 只看该作者
outer jion + null condition用在小表与大表关联,且返回数据较小的情况下效率会非常高
否则可能效率反而更底下 了

使用道具 举报

回复
论坛徽章:
1
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44
43#
发表于 2005-12-17 00:03 | 只看该作者
9i 中好像exists 与 in 基本相同!!

使用道具 举报

回复
论坛徽章:
0
44#
发表于 2006-3-21 10:42 | 只看该作者
佩服,大開眼界

使用道具 举报

回复
论坛徽章:
0
45#
发表于 2006-5-24 18:23 | 只看该作者
开眼界,其实具体情况采取具体方法.

使用道具 举报

回复
论坛徽章:
4
2010新春纪念徽章
日期:2010-03-01 11:19:502014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11ITPUB社区OCM联盟徽章
日期:2014-04-30 14:54:24
46#
发表于 2006-5-26 18:46 | 只看该作者
呵呵。 终于拜读完了。 不过还是要自己写一下。 是啊, 感觉in和exists通过执行计划看不出什么区别啊。

使用道具 举报

回复
论坛徽章:
63
19周年集字徽章-19
日期:2020-09-23 02:43:002012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-01-04 11:49:54ITPUB十周年纪念徽章
日期:2011-11-01 16:20:28现任管理团队成员
日期:2011-05-07 01:45:082011新春纪念徽章
日期:2011-02-18 11:42:472011新春纪念徽章
日期:2011-01-25 15:42:562011新春纪念徽章
日期:2011-01-25 15:42:332011新春纪念徽章
日期:2011-01-25 15:42:152011新春纪念徽章
日期:2011-01-25 15:41:50
47#
发表于 2006-5-27 00:41 | 只看该作者
还在顶啊.

使用道具 举报

回复
论坛徽章:
3
授权会员
日期:2006-04-18 13:25:09生肖徽章2007版:猴
日期:2009-02-04 17:50:05ITPUB学员
日期:2011-08-03 10:55:36
48#
发表于 2006-5-27 18:44 | 只看该作者
在测试机上测试了一把
发现和楼主测试的结构有些不同
表,索引,索引字段已经分析过.
我感觉区别在
1 NL探测Inner table的次数和这个结果记录数.
2 子查询效率,INDEX FAST FULL SCAN 代价.


[PHP]



SQL>
SQL> select count(*) from track;

  COUNT(*)
----------
  12337495

Elapsed: 00:00:00.01
SQL> select count(*) from terminal_user;

  COUNT(*)
----------
       305

Elapsed: 00:00:00.00
SQL>
SQL> set autotrace traceonly
SQL>
SQL>
SQL> select tu.* from terminal_user tu
  2   where tu.tu_id not in (select distinct tu_id from track);

36 rows selected.

Elapsed: 00:00:00.02

Execution Plan
----------------------------------------------------------

-----------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                   |    27 |  1944 |   614   (1)|
|   1 |  NESTED LOOPS ANTI |                   |    27 |  1944 |   614   (1)|
|   2 |   TABLE ACCESS FULL| TERMINAL_USER     |   305 | 20740 |     3   (0)|
|*  3 |   INDEX RANGE SCAN | TRACK_TUID_IDX |    11M|    42M|     2   (0)|
-----------------------------------------------------------------------------

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

   3 - access("TU"."TU_ID"="TU_ID"

Note
-----
   - 'PLAN_TABLE' is old version


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        627  consistent gets
          0  physical reads
         80  redo size
       4224  bytes sent via SQL*Net to client
        491  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         36  rows processed

由于terminal_user 仅有305条记录,
而且track表相关字段有索引,INDEX RANGE SCAN使得探测发挥了很高的效率.因此这个NL效率很高.
我们看到整个sql执行的Cost仅为614。


再来看 outer jion + null condition
SQL>
SQL> select tu.*
  2    from terminal_user tu,
       ( select distinct tu_id from track ) tk
where tu.tu_id = tk.tu_id(+)
   and tk.tu_id is null;  3    4    5  

36 rows selected.

Elapsed: 00:00:03.15

Execution Plan
----------------------------------------------------------

----------------------------------------------------------------------------------
| Id  | Operation               | Name              | Rows  | Bytes | Cost (%CPU)|
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |                   |    27 |  2187 | 10897  (16)|
|*  1 |  HASH JOIN RIGHT ANTI   |                   |    27 |  2187 | 10897  (16)|
|   2 |   VIEW                  |                   |   278 |  3614 | 10894  (16)|
|   3 |    HASH UNIQUE          |                   |   278 |  1112 | 10894  (16)|
|   4 |     INDEX FAST FULL SCAN| TRACK_TUID_IDX |    12M|    47M|  9365   (3)|
|   5 |   TABLE ACCESS FULL     | TERMINAL_USER     |   305 | 20740 |     3   (0)|
----------------------------------------------------------------------------------

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

   1 - access("TU"."TU_ID"="TK"."TU_ID"

Note
-----
   - 'PLAN_TABLE' is old version


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      42111  consistent gets
          0  physical reads
          0  redo size
       4224  bytes sent via SQL*Net to client
        491  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         36  rows processed

我们可以看到 select distinct tu_id from track 的访问路径为 INDEX FAST FULL SCAN
而Cost就为9365.


SQL> select distinct tu_id from track;

278 rows selected.

Elapsed: 00:00:03.27

Execution Plan
----------------------------------------------------------

--------------------------------------------------------------------------------
| Id  | Operation             | Name              | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                   |   278 |  1112 | 10894  (16)|
|   1 |  HASH UNIQUE          |                   |   278 |  1112 | 10894  (16)|
|   2 |   INDEX FAST FULL SCAN| TRACK_BK_TUID_IDX |    12M|    47M|  9365   (3)|
--------------------------------------------------------------------------------

Note
-----
   - 'PLAN_TABLE' is old version


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      42180  consistent gets
          0  physical reads
        124  redo size
       5627  bytes sent via SQL*Net to client
        667  bytes received via SQL*Net from client
         20  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        278  rows processed

SQL> select /*+ INDEX(track,TRACK_BK_TUID_IDX)*/ distinct tu_id from track
  2  ;

278 rows selected.

Elapsed: 00:00:03.69

Execution Plan
----------------------------------------------------------

-----------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                   |   278 |  1112 | 43705   (5)|
|   1 |  SORT UNIQUE NOSORT|                   |   278 |  1112 | 43705   (5)|
|   2 |   INDEX FULL SCAN  | TRACK_BK_TUID_IDX |    12M|    47M| 42176   (1)|
-----------------------------------------------------------------------------

Note
-----
   - 'PLAN_TABLE' is old version


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      41907  consistent gets
          0  physical reads
        132  redo size
       5627  bytes sent via SQL*Net to client
        667  bytes received via SQL*Net from client
         20  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        278  rows processed

我发现select distinct tu_id from track无论是FFS还是IFS效率都不怎么样.


所以这里就产生一个问题.子查询的效率会受到数据量(影响到索引段的大小)的影响.
SQL> set autotrace off
SQL> analyze index TRACK_BK_TUID_IDX validate structure;

Index analyzed.

Elapsed: 00:00:15.65

SQL> select BLOCKS,USED_SPACE,DISTINCT_KEYS,LF_ROWS_LEN from index_stats;

    BLOCKS USED_SPACE DISTINCT_KEYS LF_ROWS_LEN
---------- ---------- ------------- -----------
     42752  198198860           278   197520787


[/PHP]

所以我感觉还是多做测试,用事实说话.

使用道具 举报

回复
论坛徽章:
3
授权会员
日期:2006-04-18 13:25:09生肖徽章2007版:猴
日期:2009-02-04 17:50:05ITPUB学员
日期:2011-08-03 10:55:36
49#
发表于 2006-5-27 18:52 | 只看该作者
[PHP]
把not exists这种情况的执行计划补上.同not in这种情况

SQL> select tu.* from terminal_user tu
  2   where not exists ( select *
                      from track tk
                     where tu.tu_id = tk.tu_id);  3    4  

36 rows selected.

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------

-----------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                   |    27 |  1944 |   614   (1)|
|   1 |  NESTED LOOPS ANTI |                   |    27 |  1944 |   614   (1)|
|   2 |   TABLE ACCESS FULL| TERMINAL_USER     |   305 | 20740 |     3   (0)|
|*  3 |   INDEX RANGE SCAN | TRACK_BK_TUID_IDX |    11M|    42M|     2   (0)|
-----------------------------------------------------------------------------

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

   3 - access("TU"."TU_ID"="TK"."TU_ID"

Note
-----
   - 'PLAN_TABLE' is old version


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        628  consistent gets
          0  physical reads
        140  redo size
       4224  bytes sent via SQL*Net to client
        491  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         36  rows processed
[/PHP]

使用道具 举报

回复
论坛徽章:
0
50#
发表于 2006-9-13 17:52 | 只看该作者

我这边测试的结果正好相反

使用NOT EXISTS要比outer jion + null condition快一倍。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表