Help us understand the problem. What is going on with this article?

本番DBのデータを文字化けさせた話

実際にあったお話を供養させます。
何が原因だったのかを推測しながら読んでもらえるとポストモーテム冥利に尽きます。

経緯

混入

  • 画像コメントの文字数の上限を50文字→100文字へ増やしたいという要望が来ました。
  • 対応者は下記のようなDDLで対応することにしました。
-- テーブルはシャーディングされている
ALTER TABLE `table_1` CHANGE `image_comment` `image_comment` varchar(100) DEFAULT NULL;
ALTER TABLE `table_2` CHANGE `image_comment` `image_comment` varchar(100) DEFAULT NULL;
-- たくさんある… たくさん…
ALTER TABLE `table_100` CHANGE `image_comment` `image_comment` varchar(100) DEFAULT NULL;
  • 私はDBAのような役回りを担っており、「テスト環境でも動作確認して、問題ない」と判断しました。
  • そうしてアップデート当日を迎え、上記のDDLを流しました。
  • 無事に画像コメントの文字数上限が増えたことを本番環境で確認し、家路についたのです。

発覚

  • 翌朝、いつもどおり出社して仕事をし始める私。
  • しばらくすると上記の対応をしたスタッフがやってきて言うのです。
  • 「なんか画像のコメントが文字化けしてるみたいなんですよね…」
  • 「……?!」

調査

  • そんな馬鹿な… という思いを捨てきれず調査開始
  • 文字化けが発生しているという table_60 を確認し始める…
  • 数分後、私は衝撃の事実に気付くのです。

「うわぁあ!!」と飛び上がって驚いたのは後にも先にもこのときくらいです。

ここまで

  • 対象のテーブルはシャーディングされている
    • 私が入社する前からたくさんあります
  • 文字数を増やす対応をしただけなのに文字化けした…

    • VARCHAR 型で文字化けに関わるオプションといえば?
    • ちなみに変更したカラムの Before です
    • image_comment varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  • テスト環境でも本番環境でも確認したのに…

    • その「確認」は漏れてない?

答えに入る前に

今年のアドベントカレンダーは本番環境でやらかしちゃった人 Advent Calendar 2019 を要チェックしてます。

こういうやらかし系の共有は本当にありがたいです。

死屍累々のポストモーテム会…(゚A゚;)ゴクリ

惨劇はなぜおこってしまったのか

-- 文字化けしてないテーブル
CREATE TABLE `table_1` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  -- カラム省略
  `image_comment` varchar(100) DEFAULT NULL,
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC;
-- 文字化けしてるテーブル
CREATE TABLE `table_60` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  -- カラム省略
  `image_comment` varchar(100) DEFAULT NULL,
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ROW_FORMAT=DYNAMIC;

あ!やせいのlatin1があらわれた!

何故か一部のテーブルだけ CHARSET=utf8 COLLATE=utf8_unicode_ciではなかったのです!!

なんでかわかりませんが、昔からそうだったようです…

つまりこうなります

元々入ってた文字データ(CHARSET=utf8 COLLATE=utf8_unicode_ci)が、カラムの型変更のタイミングで文字セットを指定しなかったため、テーブルのデフォルトCHARSET=latin1 COLLATE=latin1_swedish_ciになる。

  • するとどうなる?
    • 文字が化ける
  • するとどうなる?
    • メンテが始まる

二度と惨劇を起こさないためにどうしたのか

  • シャーディングされているテーブルに齟齬がないかの確認
    • これは事件後に対応しました
    • あなたの現場のシャーディングは、大丈夫ですか?
  • 全テーブルでのデバッグ
    • 登録済みのデータが無事か、全テーブルからいくつかサンプルでレコードを取ってくるようなデバッグをすればよかったです
  • VATCHAR型, TEXT型の変更時には CHARACTER SET utf8 COLLATE utf8_unicode_ciあるいはCHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ciを入れる
    • これは今でもトラウマなのでチェックします

ひとこと

ポストモーテムを書くのも読むのもトラブルシューティング力を高めるきっかけになるかと思います!
みなさんももっと恥を忍んでさらけ出しましょう!

参考リンク

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away