选择不同的...内连接与选择...其中id在...(...)

时间:2010-04-14 16:01:24

标签: oracle select distinct inner-join materialized-views

我正在尝试创建表的子集(作为物化视图),定义为在另一个物化视图中具有匹配记录的那些记录。

例如,假设我有一个带有user_id和name列的Users表,以及一个带有entry_id,user_id,activity和timestamp列的Log表。

首先,我创建Log表的物化视图,仅选择时间戳>的那些行。 some_date。现在我想要在Log表的快照中引​​用的用户的母版化视图。我可以将其创建为

select * from Users where user_id in (select user_id from Log_mview)

或者我可以做到

select distinct u.* from Users u inner join Log_mview l on u.user_id = l.user_id

(需要使用distinct来避免来自具有多个日志条目的用户的多次点击)。

前者看起来更干净,更优雅,但需要更长时间。我错过了什么吗?有更好的方法吗?

编辑:where exists子句有很多帮助,除非条件使用OR。例如,假设上面的Log表也有一个user_name列,并且将Log条目与Users记录匹配的正确方法是列中的任何一列(用户ID或用户名)匹配。我找到了

select distinct u.* from Users u
    inner join Log_mview l
        on u.user_id = l.user_id or u.name = l.user_name

快得多
select * from Users u where exists
    (select id from Log_mview l 
        where l.user_id = u.user_id or l.user_name = u.name)

任何帮助?

(关于解释计划...... Lemme正在对它进行消毒,或者他们,而不是......我会在一段时间后发布它们。)

编辑:解释计划: 对于内部联接的查询:

Plan hash value: 436698422

---------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name                | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                     |  4539K|   606M|       |   637K  (3)| 02:07:25 |
|   1 |  HASH UNIQUE                    |                     |  4539K|   606M|  3201M|   637K  (3)| 02:07:25 |
|   2 |   CONCATENATION                 |                     |       |       |       |            |          |
|*  3 |    HASH JOIN                    |                     |  4206K|   561M|    33M|   181K  (4)| 00:36:14 |
|   4 |     BITMAP CONVERSION TO ROWIDS |                     |   926K|    22M|       |  2279   (1)| 00:00:28 |
|   5 |      BITMAP INDEX FAST FULL SCAN| I_M_LOG_MVIEW_4     |       |       |       |            |          |
|*  6 |     TABLE ACCESS FULL           | USERS               |    15M|  1630M|       | 86638   (6)| 00:17:20 |
|*  7 |    HASH JOIN                    |                     |  7646K|  1020M|    33M|   231K  (4)| 00:46:13 |
|   8 |     BITMAP CONVERSION TO ROWIDS |                     |   926K|    22M|       |  2279   (1)| 00:00:28 |
|   9 |      BITMAP INDEX FAST FULL SCAN| I_M_LOG_MVIEW_4     |       |       |       |            |          |
|  10 |     TABLE ACCESS FULL           | USERS               |    23M|  2515M|       | 87546   (7)| 00:17:31 |
---------------------------------------------------------------------------------------------------------------

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

   3 - access("U"."NAME"="L"."USER_NAME")
   6 - filter("U"."NAME" IS NOT NULL)
   7 - access("U"."USER_ID"=TO_NUMBER("L"."USER_ID"))
       filter(LNNVL("U"."NAME"="L"."USER_NAME") OR LNNVL("U"."NAME" IS NOT NULL))

Note
-----
   - dynamic sampling used for this statement

对于使用where exists的人:

Plan hash value: 2786958565

-----------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                     |     1 |   114 |    21M  (1)| 70:12:13 |
|*  1 |  FILTER                       |                     |       |       |            |          |
|   2 |   TABLE ACCESS FULL           | USERS               |    23M|  2515M| 87681   (7)| 00:17:33 |
|   3 |   BITMAP CONVERSION TO ROWIDS |                     |  7062 |   179K|     1   (0)| 00:00:01 |
|*  4 |    BITMAP INDEX FAST FULL SCAN| I_M_LOG_MVIEW_4     |       |       |            |          |
-----------------------------------------------------------------------------------------------------

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

   1 - filter( EXISTS (SELECT /*+ */ 0 FROM "MYSCHEMA"."LOG_MVIEW" 
              "LOG_MVIEW" WHERE ("USER_NAME"=:B1 OR TO_NUMBER("USER_ID")=:B2) AND 
              ("USER_NAME"=:B3 OR TO_NUMBER("USER_ID")=:B4) AND ("USER_NAME"=:B5 OR 
              TO_NUMBER("USER_ID")=:B6)))
   4 - filter("USER_NAME"=:B1 OR TO_NUMBER("USER_ID")=:B2)

Note
-----
   - dynamic sampling used for this statement

更改了DB对象名称以保护无辜者。 :P

3 个答案:

答案 0 :(得分:1)

这取决于您拥有的数据,但在联接中使用Distinct可以提高您的效果:

Select u.*
From Users u
Join ( Select Distinct user_id
       From log_mview ) l On u.user_id = l.user_id

答案 1 :(得分:1)

试试这个

select * from Users u
where exists 
   ( select user_id 
     from Log_mview l
     where l.user_id = u.user_id )
/

如果子查询返回大量行WHERE EXISTS,则可能比WHERE ... IN快得多。

答案 2 :(得分:1)

第二个查询可能比第一个查询(join + distinc)更多地使用硬盘驱动器。

第一个查询可能会转换为:

对于表中的每一行,日志在表User中找到相应的行(在内存中)。

数据库可能足够聪明,可以在用户表的内存结构中创建,这可能比Log表小得多。

我相信查询一个(join + distinct)只需要在表Log上传递一个。

distinct可能是在内存中执行的。

第二个查询可能会强制数据库对表Log执行多次读取。

所以在第二个查询中你可能得到:

对于表中的每一行,用户读取表Log(来自磁盘)中的所有行以匹配条件。

您还必须考虑由于内存可用性,负载和表增加的变化,某些查询可能会遇到速度上的显着差异。