【问题标题】:Join Two Big Tables Fast快速加入两个大表
【发布时间】:2018-11-21 02:17:08
【问题描述】:

在通过查询和进行在线研究进行研究之后,我正在向您寻求意见。期待您的回复!我正在尝试以一般方式编写此内容,因为我正在寻找有关如何执行此操作的一般想法,而不是确切的陈述。如果这个问题收到的不好,我很乐意重做,让我知道。我们开始:

我有两张桌子:

  • 表 1 有 10 条 MIO 记录。它只有一列:
    • A 列:唯一 ID(文本,例如“5uz1g09aksmsd”)
  • 表 2 有 300 条 MIO 记录。它有两列:
    • A 列:唯一 ID(文本,例如“5uz1g09aksmsd”)
    • B 列:一个数字(例如 32.5432)

目前还没有索引等,甚至没有 PK,因为这两个表都是刚刚通过 CTAS 创建的。这两个表都已分析。

我现在正在寻找一个快速查询(准备工作,例如创建索引可能需要时间,没问题)来创建第三个表,其中包含表 1 的 10 个 MIO 行,以及表 2 的 B 列(如果匹配)通过 A 列找到(99% 会找到匹配项)。为了更清楚,一个简单的 CTAS 可以是:

create table3 as
select t1.a, 
    (select t2.b from table2 t2 where t2.a = t1.a and rownum = 1)
    -- the rownum = 1 is to show Oracle that there can only be one match
from table1 t1;

这不是尽可能快(我希望)。你有什么想法让它更快?创建索引?哪个?您希望在执行计划中看到什么样的联接?哈希连接?我已经找到了

  • 创建表不记录
  • 并行查询执行和并行表创建

但我感兴趣的是,考虑到我们被允许更改系统(例如创建索引),完美执行计划的具体细节。特别是我要求 11gR2 但也非常欢迎 12c cmets。

【问题讨论】:

  • 表1到表2有外键吗?
  • @Boneist 感谢您的提问。我更新了我的问题以使其更清楚。没有外键(目前还没有,但如果您认为这会大大加快速度,我们可以创建一个)。
  • 如果我是你,鉴于列数很少,可能值得将表 1 和 2 的数据存储在索引组织的表中,而不是标准的堆表中(例如 create table_1 (column_a primary key) organization index as select ...)。请注意,这需要指定主键,但我认为这不是问题。
  • @Boneist 谢谢你的建议。明天我将尝试 IOT。你认为好处会从哪里来?表 1 作为 IOT 还是表 2 作为 IOT?或者当两者都是物联网时会有更大的好处?创建索引(T1 上的 A,T2 上的 A,B)在查询速度方面应该产生相同的结果,因为在索引访问之后不需要表访问? T1 上的索引如何提供帮助,因为无论如何我们都需要所有行?在您看来,“完美的非并行全行”执行计划是什么样的?
  • 使用 hash join 的最简单方法是使用高效的硬件使用并行查询选项。无日志记录和并行表创建的影响较小,因为经过时间的基数在连接中(简单测试)。由于表是新创建的并且仅包含相关列,因此在您的情况下,索引对哈希联接没有用(它们会比表更大)。

标签: oracle


【解决方案1】:

从使用此查询的最简单的可能性开始

create table c as 
select /*+ parallel(6) */ a.a, b.b 
from a 
left outer join b
on a.a = b.a
;

它将使用哈希连接,根据您的硬件设置调整并行度。

预期的执行计划如下

    --------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------------
|   0 | CREATE TABLE STATEMENT           |          |   261M|  6238M| 56799   (1)| 00:03:48 |        |      |            |
|   1 |  PX COORDINATOR                  |          |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)            | :TQ10002 |   261M|  6238M| 31984   (1)| 00:02:08 |  Q1,02 | P->S | QC (RAND)  |
|   3 |    LOAD AS SELECT                | C        |       |       |            |          |  Q1,02 | PCWP |            |
|*  4 |     HASH JOIN OUTER              |          |   261M|  6238M| 31984   (1)| 00:02:08 |  Q1,02 | PCWP |            |
|   5 |      PX RECEIVE                  |          |  7849K|    44M|   726   (1)| 00:00:03 |  Q1,02 | PCWP |            |
|   6 |       PX SEND HASH               | :TQ10000 |  7849K|    44M|   726   (1)| 00:00:03 |  Q1,00 | P->P | HASH       |
|   7 |        PX BLOCK ITERATOR         |          |  7849K|    44M|   726   (1)| 00:00:03 |  Q1,00 | PCWC |            |
|   8 |         TABLE ACCESS STORAGE FULL| A        |  7849K|    44M|   726   (1)| 00:00:03 |  Q1,00 | PCWP |            |
|   9 |      PX RECEIVE                  |          |   261M|  4741M| 31149   (1)| 00:02:05 |  Q1,02 | PCWP |            |
|  10 |       PX SEND HASH               | :TQ10001 |   261M|  4741M| 31149   (1)| 00:02:05 |  Q1,01 | P->P | HASH       |
|  11 |        PX BLOCK ITERATOR         |          |   261M|  4741M| 31149   (1)| 00:02:05 |  Q1,01 | PCWC |            |
|  12 |         TABLE ACCESS STORAGE FULL| B        |   261M|  4741M| 31149   (1)| 00:02:05 |  Q1,01 | PCWP |            |
--------------------------------------------------------------------------------------------------------------------------


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

   4 - access("A"."A"="B"."A"(+))

我对你大小的合成数据的测试是 35 秒。

【讨论】:

  • TYVM!我知道您说散列连接(不是嵌套循环而不是排序合并)是要走的路。我知道您在这里也看到使用索引来提高查询速度没有任何好处(我猜您的意思是它会执行 FFS,这与表上的 FTS 相同)。请问:您的查询是否会因为在 t2 中为该 t1 行找到第一个匹配项后没有告诉 Oracle 它可以停止该 t1 行而损失了大约 50% 的速度(在这里猜测)?我试图用我的 rownum = 1 告诉 Oracle,但我猜一个唯一的约束或类似的约束可以解决问题?您认为这有潜力吗?
  • 在你的情况下绝对no。已加入 probes 较小的表并扫描另一个表。第一场比赛后无需停止。如果您在Btable 中有dups,则连接将返回重复的记录。您解决的是使用INNOT EXISTS 进行查询,这会导致semianti 在您提到的第一行之后停止精确优化。
  • 我想我明白了。无论如何,它只会在表 B 中循环一次,因此在扫描 B 时“停止”没有帮助/工作。你帮了我很多,谢谢。我现在想念的最后一点是为什么表 A 上的索引(经过散列和探测的索引)不能加快速度的问题。我猜有两个问题:散列是否已经包括将记录按顺序排列?索引不能节省散列(和/或排序,如果这样做的话)的时间,因为索引可以像散列表一样被探测?泰!
  • 较小的表是 hashed (没有像我上面提到的那样进行探测,我不能再编辑它),这意味着不是排序而是直接键访问。基本上两个表都必须完全处理,即所有行。这是索引问题,而不是帮助。全表扫描规则:)
猜你喜欢
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 2017-11-19
  • 2017-05-11
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
相关资源
最近更新 更多