MySQLテナントで sql_mode パラメータによりストロングモード(STRICT_TRANS_TABLESまたはSTRICT_ALL_TABLESを設定することで有効)が有効になっている場合、DMLステートメント(INSERT、UPDATE、REPLACE、DELETEなど)や SELECT ステートメントを実行する際にデータ型変換が失敗すると、システムは異なる処理を行います。
主な違い
ステートメントタイプ |
ストロングモード OFF |
ストロングモード ON |
設計思想 |
|---|---|---|---|
| DMLステートメント (INSERT、UPDATE、DELETEなど) |
実行成功 失敗したデータをデフォルト値0で補完 警告情報を出力 |
実行失敗 全体をロールバック DMLステートメントにSELECTサブクエリが含まれる場合、その内部の型変換もストロングモードの制限を守る |
データ一貫性優先 ストロングモードではリスクのあるデータ変換を拒否 データの完全性とトランザクションの安全性を確保 |
| SELECTステートメント (クエリ操作) |
実行を続行 警告を発生 一部の結果を返すか変換を試みる |
実行を続行 警告を発生 一部の結果を返すか変換を試みる |
データクエリ操作 クエリの可用性を最優先 警告により潜在的な問題を示唆 |
ストロングモードがONの場合の動作
DMLステートメント
sql_mode にストロングモードが含まれている場合、DMLステートメントがデータ型変換失敗に遭遇すると、実行は即座に終了します。
動作特性:
- ステートメントの実行が失敗し、明確なエラーメッセージを返す
- ステートメント全体で行われた変更がロールバックされる
- データは部分的に更新されず、またターゲット列の型に合致しないデータが挿入されない
例:
INSERT INTO t (int_col) VALUES ('abc');
-- 文字列 'abc' は整数に変換できないため、失敗してエラーが発生します
UPDATE t SET date_col = '2024-02-30';
-- '2024-02-30' は無効な日付です(2月には30日がありません)、失敗してエラーが発生します
INSERT INTO t (varchar10_col) VALUES ('This string is way too long');
-- 文字列の長さがVARCHAR(10) の定義を超えているため、失敗してエラーが発生します
原理: DML操作は永続化されたデータを直接変更します。ストロングモードはデータの正確性と一貫性を保証します。誤った型変換を許可すると、データの破損や業務ロジックの違反を引き起こす可能性があるため、OceanBaseデータベースは危険な変換に遭遇すると、直ちに失敗しロールバックすることを選択しています。
SELECTステートメント
sql_mode にストロングモードが含まれている場合、SELECT ステートメントがデータ型変換失敗に遭遇した場合、DMLよりも寛容な処理を行います。
動作特性:
- ステートメントの実行は型変換失敗によって全体が中断されることはありません。
- 変換失敗した値は
NULLまたはデフォルト値として扱われます。 - 警告メッセージが生成され、
SHOW WARNINGS;で確認できます。 - クエリは実行を続け、結果セットを返します。
例:
SELECT * FROM t WHERE int_col = 'abc';
-- 'abc' は整数に変換できないため、警告が発生し、0またはNULLと見なされる可能性があります。
SELECT DATE_ADD('2024-02-30', INTERVAL 1 DAY);
-- 無効な日付で警告が発生し、関数はNULLを返します。
SELECT CAST('abc' AS UNSIGNED);
-- 文字列を符号なし整数に変換しようとすると警告が発生し、0が返されます。
原理:SELECT はクエリ操作であり、永続的なデータを変更するものではありません。主な目的は、可能な限りユーザーが確認できる結果を返すことです。厳密モードでは、SELECT は他の側面(例えば ONLY_FULL_GROUP_BY)をより重視し、型変換失敗に対しては柔軟性と部分的な結果の可用性を優先します。
厳密モードが OFF の場合の動作
DMLステートメント
非厳密モードでは、DMLステートメントが型変換失敗に遭遇しても実行は続行されます。
動作特性:
- ステートメントは正常に実行され、警告情報が出力されます。
- 変換失敗したデータは対応する型の0値に置き換えられます。
- データはテーブルに書き込まれます。
例:
CREATE TABLE test(a INT, b INT);
INSERT INTO test VALUES('abc', 'abc');
SELECT * FROM test;
実行結果:
+------+------+
| a | b |
+------+------+
| 0 | 0 |
+------+------+
1 row in set (0.039 sec)
SELECTステートメント
非厳密モードの SELECT ステートメントの動作は、厳密モードが ON の場合と似ており、警告が発生しながら実行が続行されます。
重要な注意事項
STRICT_TRANS_TABLES vs STRICT_ALL_TABLES
MySQLでは、これら2つのモードはDML動作において型変換失敗の処理が一致しています(どちらもエラーを返します)。主な違いは非トランザクションテーブル(例:MyISAM)の処理にあります。OceanBaseの基盤となるトランザクションエンジンは異なるsql_mode下でも差異がないため、OceanBaseのMySQLテナントでは、STRICT_TRANS_TABLESとSTRICT_ALL_TABLESは型変換失敗に対する動作において通常は区別がありません。
暗黙的変換ルール
変換失敗がなくても、暗黙的変換は精度損失や意味の変化を引き起こす可能性があります。厳格モードはすべての暗黙的変換を阻止するわけではなく、変換が完全に不可能であるか、データの完全な損失や無効化を引き起こす場合(例:文字列から数値への変換失敗、無効な日付、超長文字列の挿入)を主に阻止します。
明示的変換
CAST()関数を使用した明示的変換で変換失敗が発生した場合、どのステートメントタイプやsql_modeの下でもNULLを返し、警告が生成されます。これはSQL標準の動作です。
その他のモード
厳格モードは通常、ERROR_FOR_DIVISION_BY_ZEROなどの他のモードと共に設定されます。これらのモードは、ゼロ除算や無効な日付など、特定のエラー処理に影響を与えます。
故障診断
エラー(
ERROR)vs 警告(WARNING): クライアントがERRORを返す場合、DMLステートメントは完全に失敗しました。結果セットを返しながら警告が発生する場合は、SELECTステートメント内で変換問題が発生したことを意味します。sql_modeの確認:SELECT @@sql_mode;を使用して厳格モードが有効になっているか確認します。実行計画とログの確認: 複雑なケースでは、OceanBaseの実行計画出力(
EXPLAIN)がより詳細な手がかりを提供します。