查询优化 Not in to Left outer join

Posted

技术标签:

【中文标题】查询优化 Not in to Left outer join【英文标题】:Query optimization Not in to Left outer join 【发布时间】:2011-05-28 16:55:36 【问题描述】:

考虑下表;

测试

SQL> desc test;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 NUM                                       NOT NULL NUMBER
 NUM2                                               NUMBER(10)
 NUM3                                               NUMBER


       NUM       NUM2       NUM3
---------- ---------- ----------
         1          1          1
         2          2          2

测试2

SQL> desc test2;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 NUM                                       NOT NULL NUMBER
 NUM2                                      NOT NULL NUMBER
 NUM3                                               NUMBER


       NUM       NUM2       NUM3
---------- ---------- ----------
         1          1          1
         3          1          1

根据本书,如果要将 NOT IN 条件替换为 LEFT Outer join ;查询性能会提高。

解释计划 1

SQL> select * 
       from test 
      where num NOT IN (select num 
                          from test2);

NUM      NUM2       NUM3
--- --------- ----------
2          2          2

执行计划

----------------------------------------------------------
Plan hash value: 856752680

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     2 |     5   (0)| 00:00:01 |
|*  1 |  FILTER            |       |       |       |            |          |
|   2 |   TABLE ACCESS FULL| TEST  |     2 |     4 |     3   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| TEST2 |     2 |    26 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT /*+ */ 0 FROM "TEST2" "TEST2" WHERE
              LNNVL("NUM"<>:B1)))
   3 - filter(LNNVL("NUM"<>:B1))

所以我在两个表的 num 列上创建了索引,并将查询重写为:

解释计划 2

SQL> select * 
       from test 
  left join test2 on (test.num = test2.num) 
      where test2.num is null;

       NUM       NUM2       NUM3        NUM       NUM2       NUM3
---------- ---------- ---------- ---------- ---------- ----------
         2          2          2


Execution Plan
----------------------------------------------------------
Plan hash value: 1525288557

--------------------------------------------------------------------------------
| Id  | Operation                     | Name  | Rows  | Bytes | Cost (%CPU)| Tim
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |       |     2 |    82 |     4   (0)| 00:
|*  1 |  FILTER                       |       |       |       |            |
|   2 |   NESTED LOOPS OUTER          |       |     2 |    82 |     4   (0)| 00:
|   3 |    TABLE ACCESS FULL          | TEST  |     2 |     4 |     3   (0)| 00:
|   4 |    TABLE ACCESS BY INDEX ROWID| TEST2 |     1 |    39 |     1   (0)| 00:
|*  5 |     INDEX RANGE SCAN          | ID2   |     1 |       |     0   (0)| 00:
--------------------------------------------------------------------------------

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

   1 - filter("TEST2"."NUM" IS NULL)
   5 - access("TEST"."NUM"="TEST2"."NUM"(+))

我显然遗漏了一些东西,因为建议的方法被证明更昂贵。这是因为我的数据分布吗?

版本:Oracle 10g

【问题讨论】:

您已发布数据,但未发布表格信息。由于存在差异,我倾向于认为被比较的列可以为空due to the info in this article Oracle 10g ,也有问题更新:) 您的两个查询返回不同的结果集。第二个版本也从第二个表返回数据。我希望从两个表返回数据的查询比只从一个表返回数据的查询更昂贵。尝试使用 select test.* 而不是 select * 进行第二个查询,看看它是否有所作为。 @APC 是的!这就是原因,您能否将其作为答案发布,以便我接受?干杯! 【参考方案1】:

您的两个查询返回不同的结果集。第二个版本也从第二个表返回数据。我希望从两个表返回数据的查询比只从一个表返回数据的查询更昂贵。

尝试使用select test.* 而不是select * 进行第二个查询,看看它是否有所作为。

【讨论】:

以上是关于查询优化 Not in to Left outer join的主要内容,如果未能解决你的问题,请参考以下文章

LEFT OUTER JOIN 和 NOT EXISTS 查询

关于left join优化not in 导致的长时间查询无数据问题 Using where; Using join buffer (Block Nested Loop)

Sql语句优化-查询两表不同行NOT INNOT EXISTS连接查询Left Join

努力优化 Rails WHERE NOT IN 在 Rails 中的查询

Linq-to-Entities:带有 WHERE 子句和投影的 LEFT OUTER JOIN

MYSQL之not in优化方法:left join