本記事では、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行の自動インクリメント列の値を返します。
説明
これはOceanBaseデータベースとMySQLの LAST_INSERT_ID 動作における主な違いです。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 | 主キー競合 | 変更なし | 変更なし | 一致 |
| 主キー競合なし(自動インクリメント列を指定しない場合) | 最初のINSERTの自動インクリメント列の値 | 最初のINSERTの自動インクリメント列の値 | 一致 | |
| 主キー競合なし(手動で自動インクリメント列を指定した場合) | 変更なし | 最初のINSERTの自動インクリメント列の値 | OceanBaseは値を更新します | |
| REPLACE | 最初のINSERTまたは上書きされた行の自動インクリメント列の値 | 最初のINSERTまたは上書きされた行の自動インクリメント列の値 | 一致 | |
| INSERT ... ON DUPLICATE KEY | 全て競合なし | 最初のINSERTの自動インクリメント列の値 | 最初のINSERTの自動インクリメント列の値 | 一致 |
| 一部競合 | 最初のINSERTの自動インクリメント列の値 | 最初のINSERTの自動インクリメント列の値 | 一致 | |
| 全部競合 | 変更なし | 変更なし | 一致 |
互換性計画
説明
上記の動作が有効なバージョン:V4.3.3およびV4.4.1以降のバージョン。OceanBaseデータベースV4.3.5バージョンでは、V4.3.5 BP2バージョンからサポートされます。