概要
MySQLのUPDATE文でエラー(Error: 1713 SQLSTATE: HY000 (ER_UNDO_RECORD_TOO_BIG))が発生するという話。
特別特殊なことをしていないのにエラーになるので、ちょっと面食らいます。
発生条件もちょっと特殊だし。
条件
MySQL 5.7系(Aurora2も含む)、8.0系(Aurora3も含む)、8.3系
ROW_FORMAT=DYNAMIC (COMPACTは問題なし)
型=text、mediumtext (longtextは検証していません)
アップデートする前の文字列の長さ= length=7500前後。length=1000、10000は問題なし
再現
以下は、「あいう 」(utf8で3バイト、3バイト、3バイト、1バイト)で10バイト×750回の繰り返しで7500バイトのデータ例です。
CREATE DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `test` (
`id` bigint NOT NULL AUTO_INCREMENT,
`txt1` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`txt2` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
PRIMARY KEY (`id`),
KEY `idx_txt1` (`txt1`(191)),
KEY `idx_txt2` (`txt2`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
INSERT INTO
`test` (
`txt1`,
`txt2`
)
VALUES
(
repeat('あいう ', 750),
repeat('あいう ', 750)
);
UPDATE
`test`
SET
`txt1` = 'test',
`txt2` = 'test'
WHERE
`id` = 1;
ここで「Undo log record is too big.」エラーが発生します。
回避策
複数アップデートするとエラーになる
↓
1つずつアップデートすればエラーにならない
UPDATE
`test`
SET
`txt1` = 'test'
WHERE
`id` = 1;
UPDATE
`test`
SET
`txt2` = 'test'
WHERE
`id` = 1;
ワークアラウンド(回避策)としてはとてつもなくダルいですが、現時点ではこれしか回避方法がないようです。
似たような事例が公式バグリストに上がっている
Bug #88150 'Undo log record is too big.' error occurring in very narrow range of str length
上記は文字列の長さが3962〜4030の場合、と書いてあります。
違いと言えば、バージョンが違うため、innodb_file_formatが「Antelope」であること、今回はMySQL8系は固定で「Barracuda」になっています。
また、ROW_FORMATが「COMPACT」に対して、今回は「DYNAMIC」となっています。(MySQL8で「COMPACT」の場合はエラーは出ませんでした)
こちら、2017年10月に投稿されたものです。もう6年半になりますが、「Status: Verified」のままで、修正されておりません。こちらはMySQL5.5〜5.7までが対象となっています。
まさか、2024年になって、MySQL8.0(最新版の8.0.36)、8.3(最新版の8.3.0)になっても同じようなエラーが続いているとは…。
再現条件の確認
エラーになる、ならないの境界が割と謎です。
超ざっくり言えば、両方7000〜8000バイトだとエラーになる確率が高いです。
| length(txt1) | length(txt2) | 結果 |
|---|---|---|
| 7300 | 7300 | ⭕ |
| 7400 | 7400 | ❌ |
| 7500 | 7500 | ❌ |
| 7600 | 7600 | ❌ |
| 7700 | 7700 | ❌ |
| 7800 | 7800 | ❌ |
| 7900 | 7900 | ❌ |
| 8000 | 8000 | ❌ |
| 8100 | 8100 | ⭕ |
| 7300 | 8000 | ⭕ |
| 8000 | 7300 | ⭕ |
| 7400 | 8100 | ❌ |
| 8100 | 7400 | ❌ |
| 100 | 15400 | ⭕ |
| 100 | 7700 | ⭕ |
| 7000 | 7700 | ⭕ |
| 7700 | 100 | ⭕ |