本記事では、OceanBaseデータベースにおけるLAST_INSERT_ID()関数の動作と、MySQLとの違いについて説明します。
LAST_INSERT_ID()関数は、最後にINSERT操作で生成された自動インクリメントID値を取得するために使用されます。OceanBaseデータベースにおいて、この関数の動作はMySQLといくつかの点で異なり、主に以下の2つの側面で表れます:
- セッションレベルのLAST_INSERT_ID:
LAST_INSERT_ID()関数によって読み取りおよび変更されます - プロトコルレベルのLAST_INSERT_ID:MySQLプロトコルのOKパケットに返される値
MySQLの動作
セッションレベルのLAST_INSERT_ID
セッション上のLAST_INSERT_IDは、LAST_INSERT_ID(args)関数を使用して読み取りおよび変更します。
-- セッション上のLAST_INSERT_IDを読み取る
SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 0 |
+------------------+
-- 関数を使用してセッション上のLAST_INSERT_IDを変更する
SELECT LAST_INSERT_ID(10);
+--------------------+
| LAST_INSERT_ID(10) |
+--------------------+
| 10 |
+--------------------+
プロトコルレベルのLAST_INSERT_ID
MySQLプロトコルのOKパケット内のLAST_INSERT_ID。DMLステートメントがセッション上のLAST_INSERT_IDを変更した場合、DML実行後にクライアントに返されるOKパケット内のLAST_INSERT_IDは、セッション上のLAST_INSERT_IDと等しくなります。そうでない場合、クライアントに返されるLAST_INSERT_IDは、DML演算子によって書き込まれた最後の行データに対応するAUTO_INCREMENT列の値になります。
OceanBaseデータベースとMySQLの互換性
完全互換の動作
OceanBaseデータベースは、以下の点でMySQLと完全に互換性があります:
- セッションレベルの
LAST_INSERT_IDの読み取りと変更:LAST_INSERT_ID()関数を使用して、セッション上の値を読み取りおよび変更します。 - 関数式による
LAST_INSERT_ID値の設定:LAST_INSERT_ID(expr)関数を使用して値を設定します。 - プロトコルレベルのOKパケット形式:クライアントへのレスポンスパケット形式は、MySQLと一致しています。
- REPLACEステートメント:最初の行のINSERTまたは上書き書き込みの自動インクリメント列の値を返します。
- INSERT ... ON DUPLICATE KEY UPDATE:すべての競合がない場合は、最初の行のINSERTの自動インクリメント列の値を返し、一部の競合がある場合は、最初の行のINSERTの自動インクリメント列の値を返し、すべての競合がある場合は、変更されません。
- 複数行の挿入:最初の行のINSERTの自動インクリメント列の値を返します。
- IGNOREステートメント:主キーの競合によりデータが書き込まれない場合、
LAST_INSERT_IDは変更されません。
説明
セッション上では、OceanBaseもMySQLと同様にLAST_INSERT_IDを保存しており、式を使用してセッション上のLAST_INSERT_IDを取得および変更することができます。OceanBaseの動作はMySQLと完全に一致しています。
動作の違い
OceanBaseデータベースとMySQLの主な違いは、以下の点に表れます:
注意
OceanBaseは現在、クライアントへのレスポンスパケット形式においてMySQLとの互換性を保っています。つまり、OKパケット内にはLAST_INSERT_ID情報が含まれていますが、この情報の表示方法は現時点ではMySQLと完全には一致していません。DMLステートメントを使用してAUTO_INCREMENT列に書き込む際、LAST_INSERT_IDの値の変化はMySQLと完全には互換性がありません。
INSERTステートメントで自動インクリメント列を手動指定する場合
MySQLの動作:
- 自動インクリメント列を手動指定した場合:
LAST_INSERT_IDは変更されません。
OceanBaseデータベースの動作:
- 自動インクリメント列を手動指定した場合:最初の行のINSERTの自動インクリメント列の値が返されます。
説明
これは、LAST_INSERT_IDの動作におけるOceanBaseデータベースとMySQLの主な違いです。OceanBaseデータベースでは、現在の自動インクリメント列の値が手動で指定されたものか、それとも自動インクリメントサービスから取得した連番値かを区別できないため、LAST_INSERT_IDの表示においては一貫しています。
-- テストテーブルを作成
CREATE TABLE `t1` (
`c1` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`c2` INT DEFAULT NULL,
PRIMARY KEY (`c1`),
UNIQUE KEY `c2` (`c2`)
);
-- 例1:LAST_INSERT_ID関数を使用して値を変更する(MySQLとOceanBaseの動作は一致しています)
UPDATE t2 SET c1 = LAST_INSERT_ID(100) + c1 WHERE c2 = 1;
SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 100 |
+------------------+
-- 例2:INSERTステートメント(MySQLとOceanBaseの動作は一致しています)
INSERT INTO t1(c2) VALUES (1);
SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 1 |
+------------------+
-- 例3:REPLACEステートメント(MySQLとOceanBaseの動作は一致しています)
REPLACE INTO t1(c2) VALUES (2);
SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 2 |
+------------------+
-- 例4:複数行の挿入(MySQLとOceanBaseはどちらも最初の行のIDを返します)
INSERT INTO t1(c2) VALUES (3), (4);
SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 3 |
+------------------+
詳細比較表
| DMLステートメントの種類 | シナリオ | MySQLセッション上のLAST_INSERT_ID | OceanBaseセッション上のLAST_INSERT_ID | 相違点 |
|---|---|---|---|---|
| INSERT | 主キー競合 | 変更なし | 変更なし | 一致 |
| 主キー競合なし(自動インクリメント列を指定しない場合) | 1行目のINSERTによる自動インクリメント列の値 | 1行目のINSERTによる自動インクリメント列の値 | 一致 | |
| 主キー競合なし(手動で自動インクリメント列を指定した場合) | 変更なし | 1行目のINSERTによる自動インクリメント列の値 | OceanBaseは値を更新します | |
| REPLACE | 1行目のINSERTまたは上書き書き込みによる自動インクリメント列の値 | 1行目のINSERTまたは上書き書き込みによる自動インクリメント列の値 | 一致 | |
| INSERT ... ON DUPLICATE KEY | 全ての競合がない場合 | 1行目のINSERTによる自動インクリメント列の値 | 1行目のINSERTによる自動インクリメント列の値 | 一致 |
| 一部競合がある場合 | 1行目のINSERTによる自動インクリメント列の値 | 1行目のINSERTによる自動インクリメント列の値 | 一致 | |
| 全ての競合がある場合 | 変更なし | 変更なし | 一致 |
互換性計画
説明
上記の動作が有効なバージョン:V4.3.3およびV4.4.1以降のバージョン。OceanBaseデータベースV4.3.5については、V4.3.5 BP2バージョンからサポートされます。