合格基準
8問中7問正解(80%以上)で合格
これはL2月3「データの要塞を築こう」の卒業試験です。全ステップの内容を総合的に問います。
Q1: 正規化と非正規化
SNSアプリで「投稿のいいね数」をpostsテーブルにlike_countカラムとして持つ設計は、正規化の観点からどう評価されるか?
- A) 完全な正規化違反であり、絶対に避けるべき
- B) 意図的な非正規化であり、パフォーマンス上の理由で妥当
- C) 第一正規形に違反している
- D) 外部キー制約の違反である
回答と解説
正解: B
like_countは正規化の観点からは冗長(likesテーブルのCOUNTで導出可能)だが、毎回のCOUNT(*)はパフォーマンスに悪影響を与える。SNSのような読み取り頻度の高いシステムでは、意図的な非正規化として妥当な設計判断。
Q2: インデックス設計
以下のクエリに最も効果的なインデックスはどれか?
SELECT * FROM posts
WHERE user_id = 1 AND is_deleted = false
ORDER BY created_at DESC
LIMIT 20;
- A)
CREATE INDEX idx ON posts(created_at DESC) - B)
CREATE INDEX idx ON posts(user_id, created_at DESC) WHERE is_deleted = false - C)
CREATE INDEX idx ON posts(is_deleted, user_id) - D)
CREATE INDEX idx ON posts(created_at DESC, user_id)
回答と解説
正解: B
WHERE条件の user_id を先頭に、ORDER BYの created_at DESC を次に配置した複合インデックス。WHERE is_deleted = false を部分インデックスの条件にすることで、削除済み投稿を含まないコンパクトなインデックスになる。
Q3: NoSQLの選択
リアルタイムランキングシステムで「スコアの追加」「トップNの取得」「特定ユーザーの順位取得」を効率的に行うのに最適なデータストアとデータ構造はどれか?
- A) MongoDB の Collection
- B) Redis の Sorted Set
- C) PostgreSQL の通常テーブル
- D) Cassandra の Wide Column
回答と解説
正解: B
RedisのSorted Setは、スコア付きの順序付き集合。ZADD(スコア追加:O(log N))、ZREVRANGE(トップN取得:O(log N + M))、ZREVRANK(順位取得:O(log N))がすべて効率的に実行できる。
Q4: トランザクション設計
ECサイトの在庫管理で、同一商品への同時購入要求が頻繁に発生する場合、最も適切な同時実行制御はどれか?
- A) 楽観的ロック(バージョンチェック)
- B) 悲観的ロック(SELECT FOR UPDATE)
- C) ロックなし(最後の書き込みが勝つ)
- D) テーブルロック
回答と解説
正解: B
在庫管理は「衝突が頻繁」かつ「売り越しを絶対に防ぐ」必要がある。楽観的ロックではリトライが多発し効率が悪い。SELECT FOR UPDATEで行ロックを取得し、在庫確認と更新を直列化するのが最適。テーブルロックは過度に制限が強い。
Q5: 分散トランザクション
マイクロサービス構成で「注文作成 → 在庫確保 → 決済処理」の3ステップを実行する場合、最も適切なパターンはどれか?
- A) 単一DBトランザクション
- B) 2PC(Two-Phase Commit)
- C) Sagaパターン(Orchestration)
- D) ロックなしで実行
回答と解説
正解: C
マイクロサービスは各サービスが独立したDBを持つため、単一トランザクションは不可。2PCはブロッキングと可用性の問題がある。Saga(Orchestration)でローカルトランザクションを連鎖させ、失敗時は補償トランザクションで巻き戻すのが適切。
Q6: ゼロダウンタイムマイグレーション
カラム名を name から full_name に変更する際、Expand-Contract パターンの Expand フェーズで行うべきことはどれか?
- A)
ALTER TABLE users RENAME COLUMN name TO full_name - B)
ALTER TABLE users ADD COLUMN full_name VARCHAR(100)を実行し、旧カラムはそのまま残す - C)
ALTER TABLE users DROP COLUMN nameを実行する - D) アプリケーションのカラム参照を一括変更する
回答と解説
正解: B
Expand フェーズでは新しい構造(full_name カラム)を追加し、旧構造(name カラム)はそのまま残す。これによりアプリケーションは旧カラムで引き続き動作する。データ移行とアプリ切り替えは次のMigrate フェーズで行い、旧カラム削除はContract フェーズ。
Q7: バックアップとモニタリング
本番データベースの障害発生時、RPO = 5分、RTO = 30分の要件を満たすために最も適切なバックアップ戦略はどれか?
- A) 日次のフルバックアップのみ
- B) 週次のフルバックアップ + 日次の差分バックアップ
- C) 日次のフルバックアップ + WAL連続アーカイブ(PITR対応)
- D) 月次のフルバックアップのみ
回答と解説
正解: C
RPO 5分を満たすには、5分以内のデータロスに収まるバックアップが必要。WAL連続アーカイブにより、ほぼリアルタイム(WALセグメント単位)の復旧点を確保できる。日次フルバックアップと組み合わせることで、PITRで任意の時点に復旧可能。RTO 30分もPITRなら実現可能。
Q8: 総合設計判断
SNSプラットフォームのタイムライン機能で、フォロー中ユーザーの投稿を時系列で表示する場合、最も効果的なアーキテクチャはどれか?
- A) 表示時に毎回 JOIN クエリを実行する(Pull モデル)
- B) 投稿時にフォロワーのタイムラインキャッシュに追加する(Push モデル / Fan-out on Write)
- C) すべてのデータをMongoDBに格納してクエリする
- D) すべての投稿を単一テーブルに格納し、インデックスなしで検索する
回答と解説
正解: B
Fan-out on Write(Push モデル)は、投稿時にフォロワーのタイムラインキャッシュ(Redis List等)に投稿IDを追加する方式。タイムライン表示時はキャッシュを読むだけなので高速(200ms以内の要件を満たせる)。Pull モデルでは表示ごとにJOINが必要で、フォロー数が多い場合にパフォーマンスが悪化する。ただし、フォロワー数が非常に多いユーザー(100万人以上)はPull モデルと組み合わせるハイブリッド方式が実用的。
結果
合格(7問以上正解)
おめでとうございます。L2月3「データの要塞を築こう」を修了しました。
あなたは以下のスキルを習得しました:
- 正規化理論に基づくデータモデリング
- インデックスとクエリ最適化
- RDBとNoSQLの使い分け
- トランザクションとデータ整合性の設計
- 安全なマイグレーション計画
次は L2 月4 に進みましょう。
不合格(6問以下)
Step 4-5 を復習してから再挑戦してください。特に以下を重点的に:
- トランザクション設計(ロック戦略、Saga)
- ゼロダウンタイムマイグレーション
- バックアップ戦略とモニタリング
推定所要時間: 30分