こう 聞かれます
- 「サービスを
止めずに DB の スキーマを 変えるには、 どうしますか」 - 「動いている
サービスで、 列の 名前を 変えたい ときは、 どう 進めますか」 - 「スキーマの
変更と アプリの 配備は、 どちらを 先にしますか」
面接官が 見ている点
- 配備の
途中は、 古い アプリと 新しい アプリが 同時に 動く、と 分かっているか - 一度に
壊す変更を せず、 段階に 分けて 進められるか (列の 追加、 両方 への 書き込み、 移行、 読む先の 切り 替え、削除) - どの
段階でも、 1 つ前に 戻せるように しているか - 大きな
表への 変更で、 ロックが 長く かかる 危険を 知っているか
短い答え
- 一度に
壊す変更を せず、 新しい 列を 足す、 新旧の 両方に 書く、 古い データを 移す、 読む先を 新しい 列に 切り替える、 古い列を 消す、と 段階に 分けて 進めます。 - 配備の
途中は 古い アプリと 新しい アプリが 同時に 動くので、 どの 段階でも、 両方の 版が 動ける 形の スキーマに しておく 必要が あるからです。 - 段階ごとに
出して 確かめ、 何か あれば 1 つ前に 戻せるようにします。 そのかわり手間と 期間は かかるので、 止めて よい 時間を 取れる なら、 一度に 変える ほうが 早いこともあります。
少し 詳しい答え
なぜ段階に分けるか
アプリをname から full_name にname を
だから、
列の 名前を変える例
- 列を足す新しい
列を、 空 (NULL) を 許す形で 足します。 古い版は 新しい 列を 知らないので、 そのまま動きます - 両方に書く
アプリを 直して、 書く ときは 古い列と 新しい 列の 両方に 書きます。 読むのは、 まだ 古い列です - 古い
データを移す前から ある 行の 値を、 新しい 列へ 少しずつ写します - 読む先を
切り替える アプリが 新しい 列を 読むようにします。 様子を 見て、 問題が 無ければ 次へ進みます - 古い列を消す古い列を
書くのを やめ、 古い 版が どこにも 残っていないのを 確かめてから、 列を消します
SQL クエリ
-- 1 列を足す (空を許す)
ALTER TABLE users ADD COLUMN full_name TEXT;
-- 3 古いデータを少しずつ写す (1 回に写す行を絞る)
UPDATE users SET full_name = name
WHERE full_name IS NULL AND id BETWEEN 1 AND 10000;
-- 5 古い版が残っていないのを確かめてから消す
ALTER TABLE users DROP COLUMN name;どの
大きな 表で 気を つけること
行の
DB ごとに、
トレードオフ
段階に
利用者が
話すときは、
よく ある間違い
- 列の
名前を 一度に変える 配備の 途中で 動いている 古い 版が 落ちます。 足してから 消す、の 順にします - アプリを
出す前に 古い列を消す古い 版が まだ 読んでいると 落ちます。 消すのは いつも最後です - 大きな
表に、 いきなり重い 変更をかける 長いロックで 読み 書きが 止まる ことがあります。 本番に 近い量で 先に試します
深掘りの問い
- 「スキーマの
変更と アプリの 配備は、 どちらを 先にしますか」足す変更は スキーマが 先、 消す変更は アプリが 先 (古い列を 使わなくなってから 消す)、と答えます - 「途中で
問題が 出たら、 どう 戻しますか」 最後の 削除の 前なら、 アプリを 前の 版に 戻すだけで 動くように 段階を 組んでいる、と答えます - 「NOT NULL の
列を 足したいときは」 まず 空を 許して 足し、 データを 埋めてから、 NOT NULL の 制約を 付ける、と答えます