Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2767383
  • 博文数量: 389
  • 博客积分: 4177
  • 博客等级: 上校
  • 技术积分: 4773
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-16 23:29
文章分类

全部博文(389)

分类: Oracle

2013-06-29 10:16:03


               某日一开发同事反映一个SQL语句执行非常慢,语句如下.

select  count(t1.id)
  from t1 where t1.status!=0 and not exists(select 1 from
t2 where t2.id1=t1.id or t2.id2=t1.id)

表结构
create table t1
(
 id  INTEGER primary key,
 name VARCHAR2(100),
  status   INTEGER)

create table t2
(
 id1  INTEGER,
 id2   INTEGER)

t1表中数据为7296行,t2表中数据为65158行。执行时间将到了53秒

SQL> select  count(t1.id)
  2    from t1 where t1.status!=0 and not exists(select 1 from
  3  t2 where t2.id1=t1.id or t2.id2=t1.id);

COUNT(T1.ID)
------------
        7082

Elapsed: 00:00:53.74

确认了统计状态也是最新的,以及表的存储状态都没有问题
由于在那个时间段服务器资源比较空闲,就以并行的方式去执行,

SQL> select  /*+ parallel(16) */count(t1.id)
  2    from t1 where t1.status!=0 and not exists(select 1 from
  3  t2 where t2.id1=t1.id or t2.id2=t1.id);

COUNT(T1.ID)
------------
        7082

Elapsed: 00:01:03.55
发现执行速度没有明显的加快,而且时间还变长了,看来并行的方式也不合适.

 


查看执行计划

Execution Plan
----------------------------------------------------------
Plan hash value: 59119136

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     1 |     9 | 18579   (2)| 00:03:43 |
|   1 |  SORT AGGREGATE     |      |     1 |     9 |            |          |
|*  2 |   FILTER            |      |       |       |            |          |
|*  3 |    TABLE ACCESS FULL| T1   |  7296 | 65664 |     7   (0)| 00:00:01 |
|*  4 |    TABLE ACCESS FULL| T2   |     3 |    30 |     5   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   2 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE "T2"."ID2"=:B1
              OR "T2"."ID1"=:B2))
   3 - filter("T1"."STATUS"<>0)
   4 - filter("T2"."ID2"=:B1 OR "T2"."ID1"=:B2)


在这个查询中,最大的成本就在最后过滤.看来优化器也没有改写这个sql语句.没有把子查询改写成连接一类的操作.如果能去掉过滤的操作,应该能减少很多执行时间


通过该sql语句的特点,使用集合操作minus来改写not exists逻辑,语句如下

select count(*)
  from t1
 where id in (select id
                from t1
               where t1.status != 0
              minus
              select t1.id id
                from t2, t1
               where t2.id1 = t1.id
                  or t2.id2 = t1.id)

  COUNT(*)
----------
      7082

Elapsed: 00:00:00.05

改写后的执行计划

Execution Plan
----------------------------------------------------------
Plan hash value: 1961550418

---------------------------------------------------------------------------------------------
| Id  | Operation                | Name     | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |          |     1 |    19 |       |   114   (6)| 00:00:02 |
|   1 |  SORT AGGREGATE          |          |     1 |    19 |       |            |          |
|*  2 |   HASH JOIN              |          |  7296 |   135K|       |   114   (6)| 00:00:02 |
|   3 |    TABLE ACCESS FULL     | T1       |  7296 | 43776 |       |     7   (0)| 00:00:01 |
|   4 |    VIEW                  | VW_NSO_1 |  7296 | 94848 |       |   473  (79)| 00:00:06 |
|   5 |     MINUS                |          |       |       |       |            |          |
|   6 |      SORT UNIQUE         |          |  7296 | 65664 |       |            |          |
|*  7 |       TABLE ACCESS FULL  | T1       |  7296 | 65664 |       |     7   (0)| 00:00:01 |
|   8 |      SORT UNIQUE         |          | 68416 |  1069K|  1624K|   465   (2)| 00:00:06 |
|   9 |       CONCATENATION      |          |       |       |       |            |          |
|* 10 |        HASH JOIN         |          | 65158 |  1018K|       |    49   (5)| 00:00:01 |
|  11 |         TABLE ACCESS FULL| T1       |  7296 | 43776 |       |     7   (0)| 00:00:01 |
|  12 |         TABLE ACCESS FULL| T2       | 65158 |   636K|       |    41   (3)| 00:00:01 |
|* 13 |        HASH JOIN         |          |  3258 | 52128 |       |    49   (5)| 00:00:01 |
|  14 |         TABLE ACCESS FULL| T1       |  7296 | 43776 |       |     7   (0)| 00:00:01 |
|  15 |         TABLE ACCESS FULL| T2       | 65158 |   636K|       |    41   (3)| 00:00:01 |
---------------------------------------------------------------------------------------------

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

   2 - access("ID"="ID")
   7 - filter("T1"."STATUS"<>0)
  10 - access("T2"."ID2"="T1"."ID")
  13 - access("T2"."ID1"="T1"."ID")
       filter(LNNVL("T2"."ID2"="T1"."ID"))

 

可以看到已经去了filter操作,只有连接操作了,执行间还不到一秒钟就完成了.

阅读(5313) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~