作者介紹

洪燁,openGauss Contributor,多年銀行業系統架構設計及DBA實戰經驗,《DB2數據庫內部解析與性能調優》作者。openGauss的前世今生

上一篇 看到很多朋友留言對openGauss的歷史疑問較多,本文開頭就先把筆者道聽途說來的openGauss歷史作爲雜談在這裏聊聊。

華爲數據庫最早誕生於運營商的需求,最初版本名稱爲GMDB,後來基於PostgreSQL-XC進行整體改造,再配合自研的存儲引擎,發佈了FusionInsight LibrA(天枰座),也就是大家聽過較多的MPPDB,目前官網上還能找到一些FusionInsight LibrA的資料。

同時在2015年,華爲成立了另一項目組,純自研了一款與Oracle非常相似的數據庫,引擎名稱爲Zenith。在2015-2016年左右,華爲基於MySQL研發了一款雲原生數據庫TaurusDB(這個時間段貌似有三款並行的數據庫產品)。

2018年左右,華爲開始進行數據庫整合,對數據庫產品名定義爲GaussDB。針對不同的場景,分爲GaussDB 100(簡單OLTP場景,單節點架構,基於Zenith引擎)、GaussDB 200(OLAP及數倉場景,MPPDB架構,基於Libra引擎)、GaussDB 300(HTAP場景,分佈式架構,貌似是基於PostgreSQL-XL改造)三個對外的產品,在2019年又進行了再次整合,將GaussDB 100、GaussDB 300合併,產品名稱變爲GaussDB T(OLTP、HTAP場景)、GaussDB A(OLAP場景,原Gauss 200)。

之後又基於華爲雲整體策略,Zenith內核貌似是棄用了,啓用原Libra內核(內核名稱改成了軒轅),GaussDB A變成了目前的華爲雲上DWS服務,GaussDB T變成了GaussDB for openGauss服務,同時也將openGauss開源。由於openGauss是基於GMDB發展而來(也就是基於PostgreSQL的產品路線),所以命令行和元數據庫的信息看起來還是Postgres,不過底層的存儲引擎與PostgreSQL有不少改動openGauss對Oracle表的兼容性驗證

書接正傳,接着 上一篇 ,本文繼續基於openGauss 1.0.0版本對於Oracle中數據庫表的兼容性進行驗證。

數據庫的邏輯對象總共包含表、索引、約束、視圖、序列、別名、函數、存儲過程等。

表是數據庫最基本的邏輯對象,也是作爲承載數據的邏輯對象。在Oracle數據庫中,數據庫表分爲堆表、臨時表、表壓縮、索引組織表、簇表、分區表以及嵌套表等7種類型。一、堆表(heap table)

堆表是Oracle和openGauss默認表類型,堆表在數據寫入時無需考慮行存放的順序(按照寫入的時間先後順序存放),因此寫入速度較高,但由於是無序存放,讀取效率較低。在Oracle中,表的創建通常採用以下兩種方式,openGauss都可以兼容:在語句中定義表的字段結構:例如create table test(id int),這種方式也是最常見的方式;在openGauss中,執行結果如下:

postgres=# CREATE TABLE T_HEAP_TABLE

ID NUMBER,

NAME VARCHAR2(32)

);

CREATE TABLE通過select語句的查詢結果創建表:例如create table test as select * from tmp_table,openGauss中執行結果如下:

postgres=# CREATE TABLE T_HEAP_TABLE

AS

SELECT * FROM TMP_TEST;

INSERT 0 0二、臨時表

臨時表可以理解爲是一種特殊類型的表,用來保存臨時數據的一個數據庫對象。它只能存儲在臨時表空間,而非用戶的表空間,對臨時表的DML操作通常不記錄事務日誌。

Oracle臨時表分爲事務級臨時表和會話級臨時表。事務級臨時表的數據只保存在事務的生命週期中,會話級臨時表能支持會話的完整生命週期。對於這兩種級別的臨時表,openGauss都可以支持,實測結果如下:

1、事務級臨時表

此類型的臨時表中的數據僅在事務過程中有效,當事務提交後,臨時表中的數據將被自動清除,但是臨時表的結構以及元數據還存儲在用戶的數據字典中。在事務結束後,最好顯式刪除臨時表,否則數據庫會殘留臨時表的表結構和元數據。在語句中定義表的字段結構方式創建

postgres=# CREATE GLOBAL TEMPORARY TABLE T_TRANS_TMP

ID NUMBER,

NAME VARCHAR2(32)

) ON COMMIT DELETE ROWS;

CREATE TABLE通過select語句的查詢結果創建表

postgres=# CREATE GLOBAL TEMPORARY TABLE T_TRANS_TMP ON COMMIT DELETE ROWS

AS

SELECT * FROM TMP_TEST;

INSERT 0 0

2、會話級臨時表

會話級臨時表中的數據可以跨事務而存在,不過當該會話結束時,臨時表中的數據將隨着會話的結束而被丟棄。與事務級臨時表相同,在會話結束後,會話級臨時表的結構以及元數據還存儲在用戶的數據字典中,需顯式手動清除。在語句中定義表的字段結構方式創建

postgres=# CREATE TEMPORARY TABLE T_CONN_TMP

ID NUMBER,

NAME VARCHAR2(32)

) ON COMMIT PRESERVE ROWS;

CREATE TABLE通過select語句的查詢結果創建表

postgres=# CREATE TEMPORARY TABLE T_CONN_TMP ON COMMIT PRESERVE ROWS

AS

SELECT * FROM TMP_TEST;

INSERT 0 0三、表壓縮

表壓縮是對錶數據進行壓縮,達到節省空間的目的,壓縮對於數據裝載和DML操作有一定的CPU消耗。然而,這些消耗可以爲I/O的減少而抵消。Oracle常用的壓縮方式有兩種:基礎壓縮以及OLTP壓縮。

1、基礎壓縮

基礎壓縮只在direct path load的時候纔會生效,對於普通的dml語句insert、update不會發生壓縮,openGauss可以支持基礎壓縮。

postgres=# create table t_compress (id number) compress;

CREATE TABLE

2、OLTP壓縮

OLTP壓縮會對所有的DML生效,所以適用於OLTP系統。只有當新的block中的數據存放到達了閾值的時候纔會引發塊內的壓縮操作,然後更多的數據加入到塊中,再一次達到閾值,整個block會重新壓縮,以達到最大程度的壓縮級別。

這個過程會一直重複,直到Oracle數據庫確定無法再從壓縮上獲得更高的效益。所以多數OLTP事務作用在壓縮的塊上面,會和未壓縮的表上擁有相同的性能。只有部分操作會引發塊內的壓縮動作。OLTP壓縮功能openGauss目前無法支持。

postgres=# create table t_oltp_compress (id number) compress for oltp;

ERROR: syntax error at or near "for"

LINE 1: create table t_oltp_compress (id number) compress for oltp;四、索引組織表

索引組織表是以索引的方式保存表的數據,數據根據主鍵的順序進行排列的,這樣就提高了訪問的速度。缺點是由於索引塊保存所有的字段的信息,就需要更多的葉子頁面來保存數據,數據量較大的時候會造成訪問效率降低。

此外,如果主鍵頻繁修改,對應的行也就需要磁盤位置頻繁修改,行需要在不同的塊之間相互移動。通常在以下情況,會考慮使用索引組織表:表的寬度(即一行的數據長度)有限;表的主鍵不會或極少更改;表主要用於查詢,DML操作較少;大部分的業務需求是根據主鍵查詢行中其它列上的信息。

openGauss目前版本不支持索引組織表,對於應用程序來說,索引組織表的使用方式與堆表並無差異。

postgres=# CREATE TABLE T_ORG_INDEX

(

ID NUMBER,

NAME VARCHAR2(32),

PRIMARY KEY(ID)

)organization index;

ERROR: syntax error at or near "organization index"

LINE 6: )organization index;五、簇表

簇表也稱爲Cluster,在沒有數據表和索引的時候,Cluster段是可以單獨存在的。依據一定的規則,如連接鍵(Join Key),可以將多個數據表數據保存在同一個段中。並且依據一定場景實現快速檢索連接。在openGauss中,無法兼容此功能。

postgres=# create cluster t_cluster (id number) size 600;

ERROR: syntax error at or near "cluster"

LINE 1: create cluster t_cluster (id number) size 600;

在某些爲了提高連接性能的情況下,可以考慮用列存與partial cluster key結合的方式替代,表定義中可以選取某一列或幾列設置爲partial cluster key。

在導入數據時,按設置的列進行局部排序(默認每70個CU即420萬行排序一次),生成的CU會聚集在一起,即CU的min,max會在一個較小的區間內。當查詢時,where條件含有這些列時,可產生良好的過濾效果。

postgres=# CREATE TABLE WAREHOUSE

W_WAREHOUSE_SK INTEGER NOT NULL,

W_WAREHOUSE_ID CHAR(16) NOT NULL,

W_WAREHOUSE_NAME VARCHAR(20) ,

PARTIAL CLUSTER KEY(W_WAREHOUSE_SK, W_WAREHOUSE_ID)

) WITH (ORIENTATION = COLUMN);六、分區表

分區表是將一個大表按照一定的規則分解成多張具有獨立存儲空間的實體表。對於應用來說,邏輯上只有一個表,但在物理上這個表由多個物理分區組成。每個分區都是一個獨立的對象,可以獨自處理,也可以作爲一個更大對象的一部分進行處理。分區表通常分爲範圍分區、列表分區、哈希分區以及複合分區。

1、範圍分區

範圍分區就是對數據表中的某個值的範圍進行分區,根據某個值的範圍,決定將該數據存儲在哪個分區上。如根據序號分區,根據業務記錄的創建日期進行分區等(聯通每個月的賬單記錄就用的分區表存儲)。在openGauss中,可以支持範圍分區。

postgres=# CREATE TABLE t_range_partition

( prod_id NUMBER(6)

, cust_id NUMBER

, time_id DATE

, channel_id CHAR(1)

, promo_id NUMBER(6)

, quantity_sold NUMBER(3)

, amount_sold NUMBER(10,2)

) PARTITION BY RANGE (time_id)

(PARTITION sales_q1_2006 VALUES LESS THAN (TO_DATE('01-APR-2006','dd-MON-yyyy')) TABLESPACE pg_default, PARTITION sales_q2_2006 VALUES LESS THAN (TO_DATE('01-JUL-2006','dd-MON-yyyy')) TABLESPACE pg_default, PARTITION sales_q3_2006 VALUES LESS THAN (TO_DATE('01-OCT-2006','dd-MON-yyyy')) TABLESPACE pg_default, PARTITION sales_q4_2006 VALUES LESS THAN (TO_DATE('01-JAN-2007','dd-MON-yyyy')) TABLESPACE pg_default );

CREATE TABLE

2、列表分區

列表分區是根據所有可能的值,指定應該插入相應的分區,openGauss當前版本無法支持列表分區。

postgres=# CREATE TABLE t_list_partition_table

(id number,

name varchar2(20),

sales number(10, 2),

state varchar2(2))

PARTITION BY LIST (state)

(PARTITION q1_northwest VALUES ('OR', 'WA'),

PARTITION q1_southwest VALUES ('AZ', 'UT', 'NM'),

PARTITION q1_northeast VALUES ('NY', 'VM', 'NJ'),

PARTITION q1_southeast VALUES ('FL', 'GA'),

PARTITION q1_northcentral VALUES ('SD', 'WI'),

PARTITION q1_southcentral VALUES ('OK', 'TX'));

ERROR: syntax error at or near "LIST"

LINE 6: PARTITION BY LIST (state)

3、散列分區

散列(HASH)分區通過在分區鍵值上執行一個散列函數來說決定數據的物理位置。散列分區把記錄分佈在比範圍分區更多的分區上,這減少了I/O爭用的可能性。openGauss當前版本無法支持散列(HASH)分區。

postgres=# CREATE TABLE t_hash_partition

(deptno NUMBER, deptname VARCHAR(32))

PARTITION BY HASH(deptno)

(PARTITION p1 TABLESPACE pg_default, PARTITION p2 TABLESPACE pg_default,

PARTITION p3 TABLESPACE pg_default, PARTITION p4 TABLESPACE pg_default);

ERROR: syntax error at or near "HASH"

LINE 2: PARTITION BY HASH(deptno)

4、複合分區

對於分區表來說,數據傾斜的問題通常是最頭疼的。爲了解決這個問題,Oracle提供了複合分區的功能。複合分區是先使用範圍分區,然後在每個分區內再使用散列分區/列表分區的一種分區方法。不過目前版本openGauss無法支持複合分區。

postgres=# CREATE TABLE t_sub_partition

( dept_no number, country varchar2(20), sale_date date)

PARTITION BY RANGE(sale_date)

SUBPARTITION BY LIST(country)

( PARTITION q1_2012 VALUES LESS THAN('2012-Apr-01')

( SUBPARTITION q1_europe VALUES ('FRANCE', 'ITALY'),

SUBPARTITION q1_asia VALUES ('INDIA', 'PAKISTAN'),

SUBPARTITION q1_americas VALUES ('US', 'CANADA') ),

PARTITION q2_2012 VALUES LESS THAN('2012-Jul-01')

( SUBPARTITION q2_europe VALUES ('FRANCE', 'ITALY'),

SUBPARTITION q2_asia VALUES ('INDIA', 'PAKISTAN'),

SUBPARTITION q2_americas VALUES ('US', 'CANADA') ),

PARTITION q3_2012 VALUES LESS THAN('2012-Oct-01')

( SUBPARTITION q3_europe VALUES ('FRANCE', 'ITALY'),

SUBPARTITION q3_asia VALUES ('INDIA', 'PAKISTAN'),

SUBPARTITION q3_americas VALUES ('US', 'CANADA') ),

PARTITION q4_2012 VALUES LESS THAN('2013-Jan-01')

( SUBPARTITION q4_europe VALUES ('FRANCE', 'ITALY'),

SUBPARTITION q4_asia VALUES ('INDIA', 'PAKISTAN'),

SUBPARTITION q4_americas VALUES ('US', 'CANADA') ) );

ERROR: syntax error at or near "SUBPARTITION"

LINE 3: SUBPARTITION BY LIST(country)七、嵌套表

嵌套表類似C語言中的結構體,可以把一個表結構定義爲一個類型,在創建其他表的時候,可以將字段類型指向這個自定義類型。openGauss中可以通過create type進行嵌套表定義。

postgres=# CREATE TYPE t_type AS (f1 int, f2 text);

CREATE TYPE

postgres=# CREATE TABLE t_compfoo(a int, b t_type);

CREATE TABLE總結

總體而言,openGauss兼容Oracle常用表類型,索引組織表需要用集羣索引方式進行改造。對於少數非常用數據類型,需要進行少量代碼改造,可採取下列替代方案進行替換。

openGauss可替代Oracle嗎?從字段類型說起……

相關文章