[https://www.youtube.com/watch?v=jeVsB1Pc81A:embed:cite]
令和7年度 秋期 データベーススペシャリスト試験 午後Ⅰ 問3の解説動画では、稼働10年の在庫管理システムを改修するという現実的な状況を素材に、SQLによる分析処理、トランザクションの排他制御、索引設計という三つの論点がどのように一つの改善案件の中で連動するかを、問題文と解答例の流れに沿って丁寧に読み解きます。午後Ⅰの合否は、個別技術の暗記量よりも、業務要件とDBMSの内部挙動を結び付けて「なぜその設計・そのSQL・そのロック方式が必要か」を説明できるかで決まりやすく、本問はまさにその力を正面から測っています。テーマは在庫履歴の分析見直し、在庫引当処理のデッドロック対策、夜間バッチ高速化のための索引最適化で、どれも現場で頻出する一方、理解が曖昧だと誤った安心感を持ちやすい領域です。 まず設問1は、在庫履歴分析の手段を見直す場面として、日次在庫の算出と7日間の中央移動平均をSQLで生成する設計が問われます。ここでの読解ポイントは、SQLの穴埋めを単なる関数名当てにしないことです。出庫テーブル・入庫テーブルはトランザクションデータであり、同一倉庫・同一部品・同一日でも複数行が発生し得るという前提を、問題文の業務像から当然のものとして捉えます。そのため日次集計ではSUMで数量をまとめ、GROUP BYで粒度を揃えない限り、前日在庫-当日出庫+当日入庫という日次在庫の基本式が成立しません。また、LEFT OUTER JOINで突合する設計になっている以上、入出庫が発生しない日にはNULLが立つため、COALESCEで0に正規化しないと在庫数量の計算そのものがNULL伝播で崩れます。午後Ⅰでは、こうした「SQLの書き方」以上に「業務データの性質がSQLの形を決める」という理解が採点されます。 移動平均の算出では、ウィンドウ関数の枠組みを正確に読み取れるかが要点です。PARTITION BYで倉庫コードと部品番号ごとに独立した時系列を作り、ORDER BYで履歴年月日を時系列順に並べ、当日を中心に前後3日ずつの計7日をROWS BETWEEN 3 PRECEDING AND 3 FOLLOWINGでフレーミングするという構造は、中央移動平均という言葉の定義そのものです。ここで難所になりやすいのが、ウィンドウ関数は端点でも計算を返してしまうため、要件にある「計7日間のデータがそろわない期間は対象外」を満たすには、別途件数チェックが必要になる点です。CASE式のELSEをNULLにしている理由は、欠損期間を“計算はしたが信頼できない平均値”として残すのではなく、分析対象外として明示的に切り捨てるためで、COUNT(*) OVERでフレーム内件数が7未満ならNULLにするという設計は、要件とSQLの挙動を丁寧に擦り合わせた結果です。採点講評の観点で言えば、ウィンドウ関数を知っているだけでは足りず、集計範囲の端点問題を理解し、要件で求められる除外ルールをSQLで実装できるかが差になります。 次に設問2は、在庫引当APが複数同時実行された際に発生するデッドロックの原因と、対策としての楽観的ロック・悲観的ロック、さらにISOLATIONレベル変更の副作用を問う、午後Ⅰとして非常に典型的かつ得点差が出るパートです。読解ポイントは「SELECTは読むだけだから安全」という直感を捨て、共有ロックから専有ロックへの格上げが作る相互待ちを、時系列で追い切ることです。現状APは①で在庫数量を参照し、②で更新するという二段階で、①は共有ロック、②は専有ロックを必要とします。共有ロック同士は競合しないためAP1とAP2は同じ行に共有ロックを取れますが、その後どちらも専有ロックへ格上げしようとした瞬間に、互いが保持する共有ロックが障害となり、相手の解放待ちで循環が成立します。ここが「共有ロック取得→専有ロックへのアップグレード」のデッドロックという頻出パターンで、DBスペシャリストで確実に押さえるべき内部挙動です。 楽観的ロックの設計では、最終更新TS列を“バージョン”として扱う意味が問われます。参照時点でTSを取得して保持し、更新時にWHERE条件として「最終更新TS列が参照時に取得した値と一致する」ことを要求すれば、他トランザクションが先に更新してTSが変わったケースを検知して更新が0件となり、競合を顕在化できます。更新対象行が存在しない場合に①へ戻ってリトライするという流れは、ロックで直列化せず、競合時に再実行で整合性を担保するという楽観的ロックの運用そのものです。ここで大事なのは、楽観的ロックはデッドロックを“起こさない”というより、競合を“検知してやり直す”設計であり、スループットと再実行コストのトレードオフを受け入れている点です。 ISOLATIONレベルをREAD COMMITTEDに下げる案がなぜ危険かも、本問の重要論点です。RCではSELECT終了時点で共有ロックが解放されるため、AP1が在庫を読んだ後、AP2が先に在庫を減らしてしまう余地が生まれます。その結果、AP1は読んだ時点の在庫を前提に引当数量を計算し更新しようとするため、出庫可能在庫数量を超過する、すなわち過剰引当や在庫の不整合が起き得ます。デッドロックを回避するために整合性を壊すのは本末転倒であり、採点上は「ロックが減る=速い」だけで判断せず、業務制約として在庫が負数になってよいのか、引当超過が許されるのかという観点で不適切さを説明できるかが鍵になります。 悲観的ロックの対策として、SELECT時点でFOR UPDATEを指定して専有ロックを取得する案は、共有→専有の格上げをなくし、最初から更新前提のロックを確保することで、後続APを直列化しデッドロックを構造的に回避するものです。ここでの難所は、悲観的ロックは確実性が高い一方で並行性を下げるため、処理特性や競合頻度に応じて選ぶ必要があるという点で、問題文ではデッドロック頻発という状況が与えられているため、確実に止める手段として妥当性が高くなります。午後Ⅰとしては、楽観・悲観・ISOLATIONの三者を、速度ではなく整合性と競合形態の観点で使い分けて説明できることが重要です。 最後の設問3は、夜間バッチ(在庫反映AP)の高速化を図る際の索引設計が主題で、ここも「索引を増やせば速い」という短絡が通用しないことを問う構成です。並列実行の担当範囲が出庫倉庫コードと部品番号で区切られているなら、出庫テーブル側にその複合索引を設計し、自プロセスが担当する行を効率よく絞り込めるようにする必要があります。適切な索引がないと、探索が広がって本来対象外の行まで参照・ロックに巻き込み、他プロセスが更新しようとする際にロックの解放待ちが発生して全体が遅くなるという、並列化の効果を相殺する現象が起きます。この部分は、索引が性能だけでなく同時実行性にも影響するという点で、午後Ⅰの理解ポイントとして非常に重要です。 さらに処理状況列を索引に含める提案は、検索対象行を索引だけで判定できる可能性を高め、不要な表アクセスを減らす狙いがありますが、同時に更新コストを押し上げる典型的なトレードオフを生みます。処理状況は業務の進行に合わせて頻繁に更新される列であり、索引キーに含めると、UPDATEのたびに索引ツリーのメンテナンスが発生し、夜間バッチ全体の更新負荷が増えます。つまり、読み取り最適化のために書き込みを重くする判断であり、ここを「更新頻度が高い列を索引キーに含めると更新オーバーヘッドが増える」という一般論ではなく、本問の文脈で「出庫処理が進むたびに値が変わるから」という形で具体的に言えるかが採点上の強みになります。 この動画では、令和7年度 秋期 データベーススペシャリスト試験 午後Ⅰ 問3の出題趣旨に沿って、SQLの分析処理は要件の粒度と端点条件をどう実装するか、排他制御はデッドロックの原因をロックの種類と格上げで説明できるか、索引設計は並列処理・ロック競合・更新コストを同時に見て最適解を語れるか、という三つの軸で整理します。難所だったのは、個々の技術要素そのものより、要件とDBMS挙動を結び付けて「この実装で要件が満たされるのか」「性能改善のために整合性や更新性能を犠牲にしていないか」を言語化する点で、ここが午後Ⅰの合否を分けます。動画を見る意義としては、ウィンドウ関数の端点処理、共有ロックから専有ロックへの格上げが生むデッドロック、索引追加が更新性能に与える負の影響という、午後Ⅰで頻出なのに曖昧な理解のまま放置されやすい論点を、在庫管理という一つの題材の中で一貫した因果関係として理解できることにあります。これを押さえると、別年度・別題材の問題でも、SQL・トランザクション・索引を「現象→原因→対策→副作用」の順に組み立てて解ける再現性が上がり、安定して得点できる状態に近づきます。