OceanBase 連接

2021-06-09 17:48 更新

數(shù)據(jù)庫中的連接語句用于將數(shù)據(jù)庫中的兩個或多個表根據(jù)連接條件組合起來。由“連接”生成的集合, 可以被保存為表,或者當成表來使用。連接語句的含義是把兩張表的屬性通過它們的值組合在一起。數(shù)據(jù)庫中的連接類型一般包括內(nèi)連接(Inner-Join),外連接(Outer-Join),Semi 連接(Semi-Join)和 Anti 連接(Anti-Join)。其中 Semi-Join 和 Anti-Join 都是通過子查詢改寫得到,SQL 本身并沒有表述 Anti-Join 和 Semi-Join 的語法。

連接條件

連接條件可以分為等值連接(比如 t1.a = t2.b)和非等值連接(t1.a < t2.b)。相比于非等值連接條件,等值連接條件的一個好處是允許數(shù)據(jù)庫中使用高效的連接算法,比如 Hash Join 和 Merge-Sort Join。

Self-Join

Self-Join 是指跟跟自己表做連接的 Join。下面展示了一個 Self-Join 的例子。

obclient> create table t1(a int primary key, b int, c int);
Query OK, 0 rows affected (0.70 sec)

obclient> select * from t1 as ta, t1 as tb where ta.b = tb.b;

內(nèi)連接(Inner-Join)

Inner-Join 是數(shù)據(jù)庫中最基本的連接操作。內(nèi)連接基于連接條件將兩張表(如 A 和 B)的列組合在一起,產(chǎn)生新的結(jié)果表。查詢會將 A 表的每一行和 B 表的每一行進行比較,并找出滿足連接條件的組合。當連接條件被滿足,A 和 B 中匹配的行會按列組合(并排組合)成結(jié)果集中的一行。連接產(chǎn)生的結(jié)果集,可以定義為首先對兩張表做笛卡爾積(交叉連接,將 A 中的每一行和 B 中的每一行組合),然后返回滿足連接條件的記錄。

外連接(Outer-Join)

Outer-Join 并不要求連接的兩表的每一條記錄在對方表中都一條匹配的記錄。要保留所有記錄(甚至這條記錄沒有匹配的記錄也要保留)的表稱為保留表。外連接可依據(jù)連接表保留左表,右表或全部表的行而進一步分為左外連接,右外連接和全連接。其中左外連接中左表的一行未在右表中找到的時候,就在右表自動填充 NULL。右外連接中右表的一行未在左表中找到的時候,就在左表自動填充 NULL。全連接就是左表或者右表找不匹配行的時候都會自動填充 NULL。

Semi 連接 (Semi-Join)

當 A 表和 B 表進行 left/right Semi-Join 的時候,它只返回 A/B 表中所有能夠在 B/A 中找到匹配的行。Semi-Join 只能通過子查詢展開得到,如下所示。

obclient> create table t1(a int primary key, b int, c int);
Query OK, 0 rows affected (0.70 sec)

obclient> create table t2(a int primary key, b int, c int);
Query OK, 0 rows affected (0.92 sec)

obclient> insert into t1 values(1, 1, 1);
obclient> insert into t1 values(2, 2, 2);
obclient> insert into t2 values(1, 1, 1);
obclient> insert into t2 values(2, 2, 2);

--- 有依賴關(guān)系的子查詢被展開改寫成 Semi-Join
obclient> explain select * from t1 where t1.a in (select t2.b from t2 where t2.c = t1.c);
| ========================================
|ID|OPERATOR       |NAME|EST. ROWS|COST|
----------------------------------------
|0 |MERGE SEMI JOIN|    |2        |76  |
|1 | TABLE SCAN    |t1  |2        |37  |
|2 | SORT          |    |2        |38  |
|3 |  TABLE SCAN   |t2  |2        |37  |
========================================

Outputs & filters:
-------------------------------------
  0 - output([t1.a], [t1.b], [t1.c]), filter(nil),
      equal_conds([t1.a = t2.b], [t2.c = t1.c]), other_conds(nil)
  1 - output([t1.c], [t1.a], [t1.b]), filter(nil),
      access([t1.c], [t1.a], [t1.b]), partitions(p0)
  2 - output([t2.b], [t2.c]), filter(nil), sort_keys([t2.b, ASC], [t2.c, ASC])
  3 - output([t2.c], [t2.b]), filter(nil),
      access([t2.c], [t2.b]), partitions(p0)

Anti 連接(Anti-Join)

當 A 表和 B 表進行 left/right Anti-Join 的時候,它只返回 A/B 中所有不能再 B/A 中找到匹配的行。類似于 Semi-Join,Anti-Join 也只能通過子查詢展開得到,如下所示。

---有依賴關(guān)系的子查詢被改寫成 Anti-Join
obclient> explain select * from t1 where t1.a not in (select t2.b from t2 where t2.c = t1.c);
| =============================================
|ID|OPERATOR            |NAME|EST. ROWS|COST|
---------------------------------------------
|0 |HASH RIGHT ANTI JOIN|    |0        |77  |
|1 | TABLE SCAN         |t2  |2        |37  |
|2 | TABLE SCAN         |t1  |2        |37  |
=============================================

Outputs & filters:
-------------------------------------
  0 - output([t1.a], [t1.b], [t1.c]), filter(nil),
      equal_conds([t2.c = t1.c]), other_conds([t1.a = t2.b OR (T_OP_IS, t2.b, NULL, 0)])
  1 - output([t2.c], [t2.b]), filter(nil),
      access([t2.c], [t2.b]), partitions(p0)
  2 - output([t1.c], [t1.a], [t1.b]), filter(nil),
      access([t1.c], [t1.a], [t1.b]), partitions(p0)


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號