4

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

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

首先,我创建了一个 Log 表的物化视图,只选择那些时间戳 > some_date 的行。现在我想要一个在我的日志表快照中引用的用户的实体化视图。我可以将它创建为

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)

有什么帮助吗?

(关于解释计划……让我对它进行消毒,或者他们,更确切地说……我会在一段时间内发布它们。)

编辑:解释计划:对于带有内部连接的查询:

计划哈希值:436698422

-------------------------------------------------- -------------------------------------------------- ------------
| 身份证 | 操作 | 姓名 | 行 | 字节 |TempSpc| 成本 (%CPU)| 时间 |
-------------------------------------------------- -------------------------------------------------- ------------
| 0 | 选择声明 | | 4539K| 606M| | 637K (3)| 02:07:25 |
| 1 | 哈希唯一 | | 4539K| 606M| 3201M| 637K (3)| 02:07:25 |
| 2 | 串联 | | | | | | |
|* 3 | 哈希连接 | | 4206K| 561M| 33M| 181K (4)| 00:36:14 |
| 4 | 位图转换为行 | | 926K| 22M| | 2279 (1)| 00:00:28 |
| 5 | 位图索引快速全扫描| I_M_LOG_MVIEW_4 | | | | | |
|* 6 | 表访问完全 | 用户 | 15M| 1630M| | 86638 (6)| 00:17:20 |
|* 7 | 哈希连接 | | 7646K| 1020M| 33M| 231K (4)| 00:46:13 |
| 8 | 位图转换为行 | | 926K| 22M| | 2279 (1)| 00:00:28 |
| 9 | 位图索引快速全扫描| I_M_LOG_MVIEW_4 | | | | | |
| 10 | 表访问完全 | 用户 | 23M| 2515M| | 87546 (7)| 00:17:31 |
-------------------------------------------------- -------------------------------------------------- ------------

谓词信息(由操作 id 标识):
-------------------------------------------------- -

   3 - 访问("U"."NAME"="L"."USER_NAME")
   6 - 过滤器(“U”。“名称”不为空)
   7 - 访问("U"."USER_ID"=TO_NUMBER("L"."USER_ID"))
       filter(LNNVL("U"."NAME"="L"."USER_NAME") OR LNNVL("U"."NAME" IS NOT NULL))

笔记
-----
   - 用于此语句的动态采样

对于使用的人where exists

计划哈希值:2786958565

-------------------------------------------------- -------------------------------------------------- -
| 身份证 | 操作 | 姓名 | 行 | 字节 | 成本 (%CPU)| 时间 |
-------------------------------------------------- -------------------------------------------------- -
| 0 | 选择声明 | | 1 | 114 | 21M (1)| 70:12:13 |
|* 1 | 过滤器 | | | | | |
| 2 | 表访问完全 | 用户 | 23M| 2515M| 87681 (7)| 00:17:33 |
| 3 | 位图转换为行 | | 7062 | 179K| 1 (0)| 00:00:01 |
|* 4 | 位图索引快速全扫描| I_M_LOG_MVIEW_4 | | | | |
-------------------------------------------------- -------------------------------------------------- -

谓词信息(由操作 id 标识):
-------------------------------------------------- -

   1 - 过滤器(存在(选择 /*+ */ 0 从“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 - 过滤器("USER_NAME"=:B1 OR TO_NUMBER("USER_ID")=:B2)

笔记
-----
   - 用于此语句的动态采样

更改数据库对象名称以保护无辜者。:p

4

3 回答 3

1

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

Select u.*
From Users u
Join ( Select Distinct user_id
       From log_mview ) l On u.user_id = l.user_id
于 2010-04-14T16:21:33.490 回答
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.

于 2010-04-14T16:36:47.480 回答
1

第二个查询可能比第一个查询(join + distinc)更多地工作在硬盘上。

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

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

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

我相信查询一(join+distinct)只需要对表 Log 进行一次传递。

不同的可能在内存中执行。

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

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

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

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

于 2010-04-14T18:32:24.663 回答