兩張超級大表進行join的處理方式

2021-10-22 10:53:19 字數 3394 閱讀 2662

兩張超級大表join優化

乙個簡單的兩表關聯,sql跑了差不多一天一夜,這兩個表都非常巨大,每個表都有幾十個g,資料量每個表有20多億,表的字段也特別多。

相信大家也知道sql慢在**了,單個程序的pga 是絕對放不下幾十個g的資料,這就會導致消耗大量temp tablespace,sql慢就是慢在temp來回來回來回…的讀寫資料。

先建立2個測試表 t1,t2 資料來自dba_objects

create table t1 as select * from dba_objects;

create table t2 as select * from dba_objects;

我們假設 t1 和 t2 就是 兩個超級大表, 要執行的 sql: select * from t1,t2 where t1.object_id=t2.object_id;

假設t1 t2 都是幾十個gb 或者更大, 那麼***,上面的sql基本上是跑不出結果的。

有些人在想,開個並行不就得了,用並行 hash hash 演算法跑sql,其實是不可以的,原因不多說了。

我們可以利用mpp資料庫架構(greenplum/teradata/vertica)思想,或者是利用hadoop的思想來對上面的sql進行優化。

mpp架構/hadoop架構的很重要的思想就是把資料切割,把大的資料切割為很多份小的資料,然後再對小的進行關聯,那速度自然就快了。

在oracle裡面怎麼把大資料切成小資料呢,有兩個辦法,乙個是分割槽,另外乙個是分表。我這裡選擇的是分割槽,當然了看了這篇文章你也可以分表。

建立乙個表p1,在t1的表結構基礎上多加乙個欄位hash_value,並且根據hash_value進行list分割槽

create table p1(

hash_value number,

owner varchar2(30),

object_name varchar2(128),

subobject_name varchar2(30),

object_id number,

data_object_id number,

object_type varchar2(19),

created date,

last_ddl_time date,

timestamp varchar2(19),

status varchar2(7),

temporary varchar2(1),

generated varchar2(1),

secondary varchar2(1),

namespace number,

edition_name varchar2(30)

)partition by list(hash_value)

(partition p0 values (0),

partition p1 values (1),

partition p2 values (2),

partition p3 values (3),

partition p4 values (4)

)同樣的,在t2的表結構基礎上多加乙個欄位hash_value,並且根據hash_value進行list分割槽

create table p2(

hash_value number,

owner varchar2(30),

object_name varchar2(128),

subobject_name varchar2(30),

object_id number,

data_object_id number,

object_type varchar2(19),

created date,

last_ddl_time date,

timestamp varchar2(19),

status varchar2(7),

temporary varchar2(1),

generated varchar2(1),

secondary varchar2(1),

namespace number,

edition_name varchar2(30)

)partition by list(hash_value)

(partition p0 values (0),

partition p1 values (1),

partition p2 values (2),

partition p3 values (3),

partition p4 values (4)

)注意:p1和p2表的分割槽必須一模一樣

delete t1 where object_id is null;

commit;

delete t1 where object_id is null;

commit;

commit;

commit;

這樣就把 t1 和 t2的表的資料轉移到 p1 和 p2 表中了

那麼之前執行的 select * from t1,t2 where t1.object_id=t2.object_id 其實就等價於下面5個sql了

select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=0 and p2.hash_value=0;

select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=1 and p2.hash_value=1;

select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=2 and p2.hash_value=2;

select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=3 and p2.hash_value=3;

select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=4 and p2.hash_value=4;

工作中,大表拆分為多少個分割槽,請自己判斷。另外乙個需要注意的就是ora_hash函式

oracle中的hash分割槽就是利用的ora_hash函式

partition by hash(object_id) 等價於 ora_hash(object_id,4294967295)

ora_hash(列,hash桶) hash桶預設是4294967295 可以設定0到4294967295

ora_hash(object_id,4) 會把object_id的值進行hash運算,然後放到 0,1,2,3,4 這些桶裡面,也就是說 ora_hash(object_id,4) 只會產生 0 1 2 3 4

兩張超級大表join優化

乙個簡單的兩表關聯,sql跑了差不多一天一夜,這兩個表都非常巨大,每個表都有幾十個g,資料量每個表有20多億,表的字段也特別多。相信大家也知道sql慢在 了,單個程序的pga 是絕對放不下幾十個g的資料,這就會導致消耗大量temp tablespace,sql慢就是慢在temp來回來回來回.的讀寫資...

兩張表間的字段進行update

一般情況下,同一張表內的字段進行update操作是很容易的.但是兩張表之間的字段呢?稍微有點難度,今天就碰到了這種情況,要求把一張view裡的字段update到另一張table中的某個字段。首先有個比較笨點的方法,就是使用cursor 其次比較簡單有效的方法如下 update t distribut...

collection 兩張表查詢

場景 兩張表 學生基礎資訊表a,學生成績表b,兩張表通過userid關聯 返回結果 以學生為維度返回列表,學生有乙個外部屬性 成績列表 語文 100 張三 u001 成績 數學 99 英語 88 李四 u002 成績 語文 66 數學 77 英語 99 王五 u003 成績 語文 22 數學 55 ...