從 MySQL 到 OBOracle:如何處理自增列?

業務需要將數據庫轉換爲 OceanBase 數據庫,但源端涉及到 Oracle 及 MySQL 兩種不同數據庫,需要合併爲 OceanBase 中單一的 Oracle 模式,其中源端 MySQL 數據庫需要改造爲 OB Oracle 並做異構數據遷移。在數據遷移中發現,MySQL 中的自增列(AUTO_INCREMENT)在 OB Oracle 中是不支持的,在 OB Oracle 對應 MySQL 自增列的功能是通過序列實現的。通過測試以及閱讀相關文章,共測試完成了以下四種 OB Oracle 創建並使用序列的方法。

作者:楊敬博

愛可生 DBA 團隊成員,一位會攝影、會鏟屎、會打球、會騎車、生活可以自理的 DBA。

背景描述

OceanBase 數據庫中分爲 MySQL 租戶與 Oracle 租戶,本文針對 OceanBase 中 Oracle 租戶怎樣創建自增列,以及如何更簡單方便的處理自增列的問題展開介紹。OceanBase 的 Oracle 租戶以下簡稱:OBOracle

發現問題場景

業務需要將數據庫轉換爲 OceanBase 數據庫,但源端涉及到 Oracle 及 MySQL 兩種不同數據庫,需要合併爲 OceanBase 中單一的 Oracle 模式,其中源端 MySQL 數據庫需要改造爲 OB Oracle 並做異構數據遷移。在數據遷移中發現,MySQL 中的自增列(AUTO_INCREMENT)在 OB Oracle 中是不支持的,在 OB Oracle 對應 MySQL 自增列的功能是通過序列實現的。通過測試以及閱讀相關文章,共測試完成了以下四種 OB Oracle 創建並使用序列的方法。

四種 OBOracle 創建序列方法

方法一:SEQUENCE + DML

在 OceanBase 中 Oracle 數據庫,我們可以通過以下語法創建序列:

CREATE SEQUENCE sequence_name
    [
        MINVALUE value -- 序列最小值
        MAXVALUE value -- 序列最大值
        START WITH value -- 序列起始值
        INCREMENT BY value -- 序列增長值
        CACHE cache -- 序列緩存個數
        CYCLE | NOCYCLE -- 序列循環或不循環
    ]

語法解釋:

  • sequence_name 是要創建的序列名稱
  • START WITH 指定使用該序列時要返回的第一個值,默認爲 1
  • INCREMENT BY 指定序列每次遞增的值,默認爲 1
  • MINVALUEMAXVALUE 定義序列值的最小值和最大值
    • 如果序列已經遞增到最大值或最小值,則會根據你的設置進行循環或停止自增長。CACHE設置序列預讀緩存數量。
  • CYCLE 表示循環序列
  • NOCYCLE 則表示不循環序列

通過 OB 官方文檔操作,創建序列,實現表的列自增,示例如下:

obclient [oboracle]> CREATE TABLE test (
    -> ID NUMBER NOT NULL PRIMARY KEY,
    -> NAME VARCHAR2(480),
    -> AGE NUMBER(10,0)
    -> );
Query OK, 0 rows affected (0.116 sec)

obclient [oboracle]> CREATE SEQUENCE seq_test START WITH 100 INCREMENT BY 1;
Query OK, 0 rows affected (0.026 sec)

obclient [oboracle]> INSERT INTO test(ID,NAME,AGE) VALUES(seq_test.nextval, 'A',18);
Query OK, 1 row affected (0.035 sec)

obclient [oboracle]> INSERT INTO test(ID,NAME,AGE) VALUES(seq_test.nextval, 'B',19);
Query OK, 1 row affected (0.001 sec)

obclient [oboracle]> INSERT INTO test(ID,NAME,AGE) VALUES(seq_test.nextval, 'C',20);
Query OK, 1 row affected (0.001 sec)

obclient [oboracle]> select * from test;
+-----+------+------+
| ID  | NAME | AGE  |
+-----+------+------+
| 100 | A    |   18 |
| 101 | B    |   19 |
| 102 | C    |   20 |
+-----+------+------+
3 rows in set (0.006 sec)

方法二:SEQUENCE + DDL

1、首先創建一個需要自增列的表

obclient [oboracle]> CREATE TABLE Atable (
    ->         ID NUMBER(10,0),
    -> 	   	   NAME VARCHAR2(480),
    ->         AGE NUMBER(10,0),
    ->         PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.105 sec)

obclient [oboracle]> desc Atable;
+-------+---------------+------+-----+---------+-------+
| FIELD | TYPE          | NULL | KEY | DEFAULT | EXTRA |
+-------+---------------+------+-----+---------+-------+
| ID    | NUMBER(10)    | NO   | PRI | NULL     | NULL  |
| NAME  | VARCHAR2(480) | YES  | NULL | NULL    | NULL  |
| AGE   | NUMBER(10)    | YES  | NULL | NULL    | NULL  |
+-------+---------------+------+-----+---------+-------+
3 rows in set (0.037 sec)

2、創建一個序列並更改表中 ID 列的 DEFAULT 屬性爲 sequence_name.nextval

obclient [oboracle]> CREATE SEQUENCE A_seq
    -> MINVALUE 1
    -> MAXVALUE 999999
    -> START WITH 10
    -> INCREMENT BY 1;
Query OK, 0 rows affected (0.022 sec)

obclient [oboracle]> ALTER TABLE Atable MODIFY id DEFAULT A_seq.nextval;
Query OK, 0 rows affected (0.065 sec)

obclient [oboracle]> desc Atable;
+-------+---------------+------+-----+-------------------+-------+
| FIELD | TYPE          | NULL | KEY | DEFAULT           | EXTRA |
+-------+---------------+------+-----+-------------------+-------+
| ID    | NUMBER(10)    | NO   | PRI | "A_SEQ"."NEXTVAL" | NULL  |
| NAME   | VARCHAR2(480) | YES  | NULL | NULL              | NULL  |
| AGE   | NUMBER(10)    | YES  | NULL | NULL              | NULL  |
+-------+---------------+------+-----+-------------------+-------+
3 rows in set (0.013 sec)

此處爲修改表 tablename 中的 ID 值爲序列 sequence_name 的下一個值。具體而言,sequence_name.nextval 表示調用 sequence_name 序列的 nextval 函數,該函數返回序列的下一個值。因此,執行述語句後,當 tablename 表中插入一行數據時,會自動爲 ID 列賦值爲 sequence_name 序列的下一個值。

3、驗證該方法是否達到自增列的效果

obclient [oboracle]> INSERT INTO Atable(NAME,AGE) VALUES('zhangsan', 18);
Query OK, 1 row affected (0.047 sec)

obclient [oboracle]> INSERT INTO Atable(NAME,AGE) VALUES('lisi', 19);
Query OK, 1 row affected (0.002 sec)

obclient [oboracle]> select * from Atable;
+----+----------+------+
| ID | AME      | AGE  |
+----+----------+------+
| 10 | zhangsan |   18 |
| 11 | lisi     |   19 |
+----+----------+------+
2 rows in set (0.013 sec)

方法三:SEQUENCE + 觸發器

OB 延用 Oracle 中創建觸發器的方法達到自增列的效果,具體步驟如下:

1、首先創建一個序列:

obclient [oboracle]> CREATE SEQUENCE B_seq
    -> MINVALUE 1
    -> MAXVALUE 999999
    -> START WITH 1
    -> INCREMENT BY 1;
Query OK, 0 rows affected (0.023 sec)

2、創建一個表:

obclient [oboracle]> CREATE TABLE Btable (
    ->   ID NUMBER,
    ->   NAME VARCHAR2(480),
    ->   AGE NUMBER(10,0)
    -> );
Query OK, 0 rows affected (0.129 sec)

3、創建一個觸發器,在每次向表中插入行時,觸發器將自動將新行的 ID 列設置爲序列的下一個值。

obclient [oboracle]> CREATE OR REPLACE TRIGGER set_id_on_Btable
    -> BEFORE INSERT ON Btable
    -> FOR EACH ROW
    -> BEGIN
    ->   SELECT B_seq.NEXTVAL INTO :new.id FROM dual;
    -> END;
    -> /
Query OK, 0 rows affected (0.114 sec)

該觸發器在每次向 Btable 表中插入行之前觸發,通過 SELECT B_seq.NEXTVAL INTO :new.id FROM dual;ID 列設置爲 B_seq 序列的下一個值。:new.id 表示新插入行的 id 列,dual 是一個虛擬的表,用於生成一行數據用以存儲序列的下一個值。

4、驗證該方法是否達到自增列的效果

obclient [oboracle]> INSERT INTO Btable(NAME,AGE) VALUES('zhangsan', 18);
Query OK, 1 row affected (0.111 sec)

obclient [oboracle]> INSERT INTO Btable(NAME,AGE) VALUES('lisi', 19);
Query OK, 1 row affected (0.002 sec)

obclient [oboracle]> select * from Btable;
+------+----------+------+
| ID   | NAME     | AGE  |
+------+----------+------+
|    1 | zhangsan |   18 |
|    2 | lisi     |   19 |
+------+----------+------+
2 rows in set (0.008 sec)

方法四:GENERATED BY DEFAULT AS IDENTITY 語法

1、在創建表時使用 GENERATED BY DEFAULT AS IDENTITY 語法來創建自增長的列

obclient [oboracle]> CREATE TABLE Ctable (
    -> ID NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 999999 INCREMENT BY 1 START WITH 1 primary key,
    -> NAME VARCHAR2(480),
    -> AGE NUMBER(10,0)
    -> );
Query OK, 0 rows affected (0.121 sec)

obclient [oboracle]> desc Ctable;
+-------+---------------+------+-----+------------------+-------+
| FIELD | TYPE          | NULL | KEY | DEFAULT          | EXTRA |
+-------+---------------+------+-----+------------------+-------+
| ID    | NUMBER        | NO   | PRI | SEQUENCE.NEXTVAL | NULL  |
| NAME  | VARCHAR2(480) | YES  | NULL | NULL             | NULL  |
| AGE   | NUMBER(10)    | YES  | NULL | NULL             | NULL  |
+-------+---------------+------+-----+------------------+-------+
3 rows in set (0.011 sec)

2、驗證該方法是否達到自增列的效果

obclient [oboracle]> INSERT INTO Ctable(NAME,AGE) VALUES('zhangsan', 18);
Query OK, 1 row affected (0.015 sec)

obclient [oboracle]> INSERT INTO Ctable(NAME,AGE) VALUES('lisi', 19);
Query OK, 1 row affected (0.001 sec)

obclient [oboracle]> select * from Ctable;
+----+----------+------+
| ID | NAME     | AGE  |
+----+----------+------+
| 1  | zhangsan |   18 |
| 2  | lisi     |   19 |
+----+----------+------+
2 rows in set (0.008 sec)

3、通過驗證,使用 GENERATED BY DEFAULT AS IDENTITY 可以非常簡單地創建自增長列,無需使用其他手段,例如觸發器。此方法不需要手動創建序列,會自動創建一個序列,在內部使用它來生成自增長列的值。

obclient [SYS]>  select * from dba_objects where OBJECT_TYPE='SEQUENCE';
+-------+-----------------+----------------+------------------+----------------+-------------+-----------+---------------+------------------------------+--------+-----------+-----------+-----------+-----------+--------------+
| OWNER | OBJECT_NAME     | SUBOBJECT_NAME | OBJECT_ID        | DATA_OBJECT_ID | OBJECT_TYPE | CREATED   | LAST_DDL_TIME | TIMESTAMP                    | STATUS | TEMPORARY | GENERATED | SECONDARY | NAMESPACE | EDITION_NAME |
+-------+-----------------+----------------+------------------+----------------+-------------+-----------+---------------+------------------------------+--------+-----------+-----------+-----------+-----------+--------------+
| MYSQL | A_SEQ           | NULL           | 1100611139403783 |           NULL | SEQUENCE    | 31-MAY-23 | 31-MAY-23     | 31-MAY-23 02.21.42.603005 PM | VALID  | N         | N         | N         |         0 | NULL         |
| MYSQL | B_SEQ           | NULL           | 1100611139403784 |           NULL | SEQUENCE    | 31-MAY-23 | 31-MAY-23     | 31-MAY-23 03.28.39.222090 PM | VALID  | N         | N         | N         |         0 | NULL         |
| MYSQL | ISEQ$$_50012_16 | NULL           | 1100611139403785 |           NULL | SEQUENCE    | 31-MAY-23 | 31-MAY-23     | 31-MAY-23 04.01.23.577766 PM | VALID  | N         | N         | N         |         0 | NULL         |
| MYSQL | SEQ_TEST        | NULL           | 1100611139403786 |           NULL | SEQUENCE    | 31-MAY-23 | 31-MAY-23     | 31-MAY-23 05.09.33.981039 PM | VALID  | N         | N         | N         |         0 | NULL         |
+-------+-----------------+----------------+------------------+----------------+-------------+-----------+---------------+------------------------------+--------+-----------+-----------+-----------+-----------+--------------+
6 rows in set (0.042 sec)

查看數據庫對象視圖 dba_objects,發現該方法通過創建對象內部命名方式爲 ISEQ$$_5000x_16

測試發現,關於序列對象的名稱在OB中不論是通過 GENERATED BY DEFAULT AS IDENTITY 自動創建,還是手動創建,都會佔用 ISEQ$$_5000x_16x 的位置,若刪除序列或刪除表,該對象名稱也不會複用,只會單調遞增。

Tips:

在 Oracle 12c 及以上版本中,可以使用 GENERATED BY DEFAULT AS IDENTITY 關鍵字來創建自增長的列;

在 PostgreSQL 數據庫中 GENERATED BY DEFAULT AS IDENTITY 也是適用的。

總結

  • 方法一(SEQUENCE + DML):也就是 OB 的官方文檔中創建序列的操作,在每次做 INSERT 操作時需要指定自增列並加入 sequence_name ,對業務不太友好,不推薦

  • 方法二(SEQUENCE + DDL):相較於第一種該方法只需要指定 DDL 改寫 DEFAULT 屬性省去了 DML 的操作,但仍需再指定自己創建的序列名 sequence_name,每個表的序列名都不一致,管理不方便,不推薦

  • 方法三(SEQUENCE + 觸發器)延用 Oracle 的序列加觸發器的方法,觸發器會佔用更多的計算資源和內存,對性能會有影響,因此也不推薦

  • 方法四(GENERATED BY DEFAULT AS IDENTITY 語法):既方便運維人員管理,對業務也很友好,還不影響性能。強烈推薦!!!

以上就是對 OBOracle 中如何創建自增列的幾種方法的總結。有需要的小夥伴可以試試(●'◡'●)。

本文關鍵字:#Oceanbase# #Oracle# #創建自增#

關於 SQLE

愛可生開源社區的 SQLE 是一款面向數據庫使用者和管理者,支持多場景審覈,支持標準化上線流程,原生支持 MySQL 審覈且數據庫類型可擴展的 SQL 審覈工具。

SQLE 獲取

類型 地址
版本庫 https://github.com/actiontech/sqle
文檔 https://actiontech.github.io/sqle-docs/
發佈信息 https://github.com/actiontech/sqle/releases
數據審覈插件開發文檔 https://actiontech.github.io/sqle-docs-cn/3.modules/3.7_auditplugin/auditplugin_development.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章