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)がより詳細な手がかりを提供します。