戦国IT

情報処理技術者試験の過去問対策サイト

データベーススペシャリスト試験 2017年 午後102


トランザクションの排他制御に関する次の記述を読んで, 設問1〜3に答えよ。

 Y社は, オフィスじゅう器メーカである。 現在, 在庫管理システムのアプリケーションプログラム (以下, AP という) の改修を実施している。  
〔在庫管理システムのテーブル〕  在庫管理システムの主なテーブル構造を,図1に示す。 各テーブルには主索引が定義されている。
データベーススペシャリスト試験(平成29年 午後I 問2 図1)
〔在庫管理業務の概要〕 (1) 各地の生産拠点には,組立工場と,これに隣接する倉庫がそれぞれ一つ配置されている。 (2) 倉庫からの部品の出庫には, 倉庫から隣接する組立工場に出庫する場合と,倉庫から他の生産拠点の倉庫に出庫する場合がある。 (3) 倉庫は,倉庫コードで一意に識別され,組立工場は,工場コードで一意に識別される。 生産拠点を識別するコードは存在しない。 (4) 定期便は, 倉庫間で部品を配送する便であり,便番号で一意に識別される。 (5) 部品は,部品番号で一意に識別される。 (6) 部品の在庫は, 倉庫と部品の組合せで,その数量をもつ。 倉庫内に存在する在庫を,倉庫内在庫と呼ぶ。 このうち, 隣接する組立工場又は他の生産拠点の倉庫に向けて出庫対象となったものを, 出庫対象在庫と呼ぶ。 (7) 出庫要求とは,倉庫に対して部品の出庫を要求することである。 “出庫” テーブルに出庫要求の内容が登録され, 処理状況に ‘要求発生' が記録される。 出庫番号は,出庫要求の発生順の一意な連番である。 組立工場が出庫要求する場合, 出庫先倉庫コード及び出庫便番号の値は NULL となり, 出庫先工場コードが記録される。他の生産拠点の倉庫が出庫要求する場合, 出庫先工場コードは NULL となり,出庫先倉庫コードが記録され, 出庫便番号には該当する定期便の便番号が記録される。 (8) 在庫引当とは, 出庫要求に応じて倉庫内の在庫を引き当てることである。 在庫引当 AP は,毎日の業務中に定期的に実行され, その時点で登録されている出庫要求を処理する。 指定された倉庫コード, 部品番号, 出庫数量の出庫が可能かどうかチェックし、出庫可能であれば出庫対象在庫数量を更新する。 在庫引当が完了したら,処理状況は ‘引当実施' に更新される。 (9) 出庫とは, 出庫要求に従って, 倉庫から部品を出すことである。 出庫は多頻度で行われるので, 出庫ごとに在庫は更新されず, 出庫確定 AP でまとめて更新される。 (10) 出庫確定 AP は、 毎日の業務終了時に実行される。 “出庫” テーブルの処理状況が ‘引当実施' のものを対象に, 倉庫内在庫数量及び出庫対象在庫数量が更新され,処理が完了したら, 処理状況は ‘出庫実施’に更新される。 (11) 入庫とは,他の生産拠点の倉庫で出庫された部品を倉庫に入れることである。入庫による在庫の更新は,在庫引当 AP 及び出庫確定 AP と同時に実行されることはない。  
〔RDBMS の排他制御〕 (1) 在庫管理システムの RDBMS で選択できるトランザクションの ISOLATION レベルとその排他制御は,表1のとおりである。  ロックは行単位で掛ける。 共有ロックが掛かっている間, 他のトランザクションからの対象行の参照は可能であり,更新は共有ロックの解放待ちとなる。 専有ロックが掛かっている間, 他のトランザクションからの対象行の参照, 更新は専有ロックの解放待ちとなる。
データベーススペシャリスト試験(平成29年 午後I 問2 表1)
(2) 索引を使わずに, テーブルスキャンで全ての行に順次アクセスする場合, 検索条件に合致するか否かにかかわらず全行がロック対象となる。 索引スキャンの場合,索引から読み込んだ行だけがロック対象となる。  
〔分析機能の追加〕  適切な生産計画を立てるために, 部品ごとに在庫数量, 出庫数量の日別の推移状況を見たいという要望があり,そのための集計 AP を追加した。 集計 AP で実行するSQL の一部を, 表2に示す。 SQL1 は各部品の出庫年月日ごとの出庫数量を集計する。  また, SQL1 では、 出庫が全くない部品も集計対象とする。 SQL2 は, 各部品の倉庫間の出庫について, 出庫年月日,出庫元倉庫, 出庫先倉庫ごとに出庫数量を集計する。表2 集計 AP で実行する SQL の構文 (未完成)
データベーススペシャリスト試験(平成29年 午後I 問2 表2)
〔在庫引当 AP の改修〕  在庫管理システムでは, トランザクションの ISOLATION レベルを REPEATABLEREAD として設計, 運用していた。 システムの改修に当たり,在庫引当 AP のトランザクションの ISOLATION レベルを READ COMMITTED に変更することにした。ISOLATION レベルの変更で問題が発生しないように在庫引当AP を改修した。  改修前の在庫引当 AP は図 2, 改修後の在庫引当AP は図3のとおりである。 これらの AP の実行に先立って, “出庫” テーブルの処理状況が ‘要求発生' の行を抽出し、出庫先倉庫ごとに分割したファイルを作成する。 それぞれのファイルのレコードは,出庫番号順に記録されている。 作成したファイルを入力として, 在庫引当 AP を並列実行している。 在庫引当 AP は, 入力ファイルのレコードごとに繰り返し実行される。  なお,図 2,3中のホスト変数 hv0 は出庫番号, hv1 は出庫元倉庫コード, hv2 は部品番号, hv3 は出庫数量を表す。 hv4 と hv5 は, 検索結果を返す出力ホスト変数を表す。
データベーススペシャリスト試験(平成29年 午後I 問2 図2)
データベーススペシャリスト試験(平成29年 午後I 問2 図3)   〔出庫確定 APの改修 〕  出庫確定 AP の処理に掛かる時間を短縮するために, 出庫確定 AP を並列に多重プロセスで実行するように変更することにした。 “出庫” テーブルの出庫番号の値の範囲指定で各プロセスに均等に配分して, REPEATABLE READ で並列実行する。 出庫確定 AP の概要は,図4のとおりである。
データベーススペシャリスト試験(平成29年 午後I 問2 図4)

トランザクションの排他制御に関する次の記述を読んで, 設問1〜3に答えよ。

設問1

〔分析機能の追加〕について,表 2 中の(a)〜(e)に入れる適切な字句を答えよ。

模範解答

a:SUM(S.出庫数量) b:LEFT OUTER JOIN c:GROUP BY B.部品番号,S.出庫年月日 d:出庫便番号 e:NOT NULL

解説

解答の論理構成

  1. 出庫数量の集計列
    【問題文】では「SQL1 は各部品の出庫年月日ごとの出庫数量を集計する。」とあります。したがって (a) には数量の合計を返す
    SUM(S.出庫数量)
    が入ります。
  2. 結合種別の決定
    「SQL1 では、出庫が全くない部品も集計対象とする。」と指示されています。これは基準表(在庫)に存在するが従表(出庫)に行が存在しないケースも取り込む必要があるため、(b) には
    LEFT OUTER JOIN
    を置きます。
  3. 集計単位の指定
    集計単位は「各部品の出庫年月日ごと」ですから、(c) の
    GROUP BY
    句には
    B.部品番号,S.出庫年月日
    を列挙します。
  4. 倉庫間出庫の抽出条件
    SQL2 について【問題文】には「倉庫間の出庫」を対象とするとあります。倉庫間出庫は便が割り振られるケースであり、便番号が
    NULL
    でない行が条件になります。従って (d) は
    出庫便番号
    , (e) は
    NOT NULL
    です。

誤りやすいポイント

  • 内部結合
    INNER JOIN
    を選んでしまい、出庫が無い部品が欠落する。
  • GROUP BY
    B.倉庫コード
    を含めてしまうなど、要件外の列を入れて集計粒度を細かくしてしまう。
  • (d) IS (e)
    を「
    出庫便番号 IS NULL
    」と誤記し、倉庫間ではなく工場向け出庫を抽出してしまう。
  • SUM
    句でエイリアスを付け忘れ、後続の帳票処理で列名が合致しなくなる。

FAQ

Q:
LEFT OUTER JOIN
RIGHT OUTER JOIN
のどちらを使っても良いですか?
A: 基準表を「在庫」にしたいので
LEFT OUTER JOIN
が妥当です。
RIGHT
を用いる場合はテーブルの左右を入れ替える必要があり、可読性が下がります。
Q:
出庫便番号
NULL
で無いことだけで倉庫間出庫と断定できますか?
A: 【問題文】には「他の生産拠点の倉庫が出庫要求する場合,… 出庫便番号には該当する定期便の便番号が記録される。」と明記されています。よって
NOT NULL
条件で倉庫間出庫を抽出できます。
Q: SQL1 の
SUM(S.出庫数量)
は 0 行の場合どうなりますか?
A:
LEFT OUTER JOIN
で結合できない行は
NULL
を返し、
SUM
NULL
を結果にします。必要に応じて
COALESCE
で 0 に置き換える実装も考えられます。

関連キーワード: 外部結合, 集約関数, NULL判定, グループ化, 結合条件

設問2〔在庫引当 AP の改修〕について,(1)〜(3)に答えよ。

(1)図2の改修前の在庫引当 AP が, REPEATABLE READ で複数同時に実行されるとデッドロックが発生するおそれがある。 どのような場合にデッドロックが発生するか, AP 間の SQL の実行状況を、 図2中の丸数字を用いて 60字以内で述べよ。

模範解答

“在庫”テーブルの同じ行に対して,先行するAPの①と②の間で,後続のAPの①が実行された場合

解説

解答の論理構成

  1. ①の役割
    【問題文】「データ参照時に共有ロックを掛け,トランザクション終了時に解放する。」
    → 図2の①は SELECT なので同一行に共有ロックが掛かり、トランザクション中保持され続けます。
  2. ②の役割
    【問題文】「データ更新時に専有ロックを掛け,トランザクション終了時に解放する。」
    → 図2の② UPDATE では専有ロックへの昇格が必要です。
  3. 複数 AP の同時実行
    • 先行 AP:①で共有ロック取得 →②で専有ロック待ち
    • 後続 AP:①で共有ロック取得(先行 AP の②がまだ実行前なので取得可)→②で専有ロック待ち
  4. 循環待ちの成立
    先行 AP は後続 AP の共有ロック解放を、後続 AP は先行 AP の共有ロック解放を待つ状態となり、デッドロックが完成します。
  5. したがって模範解答「“在庫”テーブルの同じ行に対して,先行するAPの①と②の間で,後続のAPの①が実行された場合」が成立します。

誤りやすいポイント

  • SELECT はロックを掛けないと誤解し、「共有ロック」を忘れる。
  • 「READ COMMITTED」なら共有ロックはすぐ解放されるが、設計は「REPEATABLE READ」である点を見落とす。
  • ファイル分割で AP を並列にしているから同じ行には触れないと決めつけてしまう。
  • ロックの粒度が「行単位」であることを意識せず、テーブル全体で考えてしまう。

FAQ

Q: ②がロック昇格待ちになる理由は何ですか?
A: UPDATE は共有ロックでは実行できず、同じ行への「専有ロック」が必要だからです。共有ロックが残っている限り昇格できません。
Q: 「READ COMMITTED」に変更すればデッドロックはなくなりますか?
A: ①の共有ロックが参照終了時に解放されるためデッドロックの確率は下がりますが、タイミングによっては依然として発生し得ます。そこで図3のようにカーソル FOR UPDATE を用いてロック取得の粒度とタイミングを調整します。

関連キーワード: 共有ロック, 専有ロック, ロック昇格, デッドロック, トランザクション隔離レベル

設問2〔在庫引当 AP の改修〕について,(1)〜(3)に答えよ。

(2)図2の改修前の在庫引当 AP が, READ COMMITTED で同じ倉庫の同じ部品に対して複数同時に実行されると, 在庫数量が不正になるおそれがある。 在庫数量が不正になる AP の実行状況を図5に示す。 不正になるのは, AP2 の①〜④の各SQL が, t2, t4, t6, t8 のどの時間帯で実行された場合か, 該当する時間帯に①〜④を記入せよ。 ここで,一つの時間帯に複数の SQL を実行できる。  また,この状況が発生した場合の, 在庫数量が不正とは具体的にどのような状態か, 30字以内で述べよ。 データベーススペシャリスト試験(平成29年 午後I 問2 図5)

模範解答

実行状況: データベーススペシャリスト試験(平成29年 午後I 問2 設問2-2)
状態:出庫対象在庫数量が倉庫内在庫数量を超える。

解説

解答の論理構成

  1. ロック動作の整理
    • READ COMMITTED … 「データ参照時に共有ロックを掛け,参照終了時に解放する。」
    • FOR UPDATE
      … 「FETCH された行に専有ロックが掛かる。」
  2. AP1 の進行(t1→t7)
    SELECT … FOR UPDATE
    で在庫行に専有ロック
    ② 出庫対象在庫数量を加算
    ③ “出庫” を更新
    COMMIT
    でロック解放
  3. AP2 の競合シナリオ
    • t2 で「①」を発行 → 専有ロック待ちで 待機
    • t7 で AP1 が
      COMMIT
      → ロック解放
    • t8 で AP2 の FETCH 完了(加算済みの在庫を取得)→ ②③④ を連続実行
  4. 結果
    AP2 は AP1 の加算を認識できず 再度加算。倉庫内在庫数量は変わらないまま、
    出庫対象在庫数量 = 以前の値+hv3(AP1)+hv3(AP2)
    したがって「出庫対象在庫数量が倉庫内在庫数量を超える。」

誤りやすいポイント

  • 「専有ロックを掛ければ同時実行は起きない」と思い込み、
    COMMIT
    後の非再現読を見落とす。
  • REPEATABLE READ と READ COMMITTED のロック解放タイミングを混同する。
  • CLOSE
    した時点でロックが解放されると誤解する(実際はトランザクション終了時)。

FAQ

Q: t2 で AP2 の「①」が実行できるのはなぜですか?
A: 実行自体は可能ですが在庫行は専有ロック中なので 待機状態 になります。ロックが解放される t7 まで FETCH 完了は遅延します。
Q: REPEATABLE READ に戻せば問題は解決しますか?
A: はい。REPEATABLE READ では「データ参照時に共有ロックを掛け,トランザクション終了時に解放する。」ので AP2 が t2 で取得する在庫値は AP1 の更新前に固定され、二重加算が起きません。
Q: アプリ側で対策する方法はありますか?
A: 例として「在庫−出庫対象在庫数量」を条件に
UPDATE … WHERE … AND 倉庫内在庫数量−出庫対象在庫数量 >= :hv3
のように 更新側で在庫残を再チェック すれば、ロック競合後でも不整合を防げます。

関連キーワード: トランザクション分離レベル, 共有ロック, 専有ロック, ロストアップデート, 排他制御

設問2〔在庫引当 AP の改修〕について,(1)〜(3)に答えよ。

(3)図3中の(f)に入れる適切な字句を答えよ。

模範解答

f:CURRENT

解説

解答の論理構成

  1. 図3の該当部分を確認
    UPDATE 在庫 SET 出庫対象在庫数量 = 出庫対象在庫数量 + :hv3
        WHERE (f) OF 在庫カーソル
    
    ここで
    (f)
    は、直前に
    FETCH
    した行だけを更新対象とするための句です。
  2. カーソル宣言の条件
    DECLARE 在庫カーソル CURSOR
        FOR SELECT ... FROM 在庫 ... FOR UPDATE
    
    問題文には「在庫カーソルに
    FOR UPDATE
    を指定した場合、FETCH された行に専有ロックが掛かる。」とあります。
    FOR UPDATE
    が付いたカーソルで直前にフェッチした行を特定する標準句は
    WHERE CURRENT OF
    です。
  3. 標準 SQL ルール
    • WHERE CURRENT OF <cursor_name>
      は、そのカーソルで最後にフェッチした行のみを対象に
      UPDATE
      または
      DELETE
      を行う。
    • これにより主キーを再指定せずとも対象行を一意に特定でき、排他ロックも保持される。
  4. 以上より
    (f)
    には
    CURRENT
    を補完するのが正答となります。

誤りやすいポイント

  • WHERE ROWID = :host_var
    のように行識別子で更新しようとすると、ロックを保持する保証がなく READ COMMITTED では競合を招く恐れがあります。
  • CURRENT
    だけではなく
    WHERE CURRENT OF <カーソル名>
    が完全形であることを忘れ、句全体を記述してしまう。
  • FOR UPDATE
    がないカーソルで
    WHERE CURRENT OF
    を使用できると誤解する(多くの RDBMS でエラー)。

FAQ

Q:
WHERE CURRENT OF
句を使うとき、主キー索引は不要ですか?
A: 不要です。カーソルが保持しているカーソルポインタ情報で行を特定できるため、主キーや索引を再指定する必要はありません。
Q: READ COMMITTED に変更しても一貫性は保てますか?
A: はい。
FOR UPDATE
によりフェッチ時点で対象行に専有ロックが掛かり、
COMMIT
まで解放されないため、同一行に対する他プロセスの更新は待機します。
Q:
CURRENT OF
CURRENT
だけの違いは?
A:
UPDATE ... WHERE CURRENT OF <カーソル名>
が正式構文です。本設問ではテンプレート中に
OF 在庫カーソル
が既に書かれているため、空所
(f)
には「
CURRENT
」のみを挿入します。

関連キーワード: カーソル操作, WHERE CURRENT OF, FOR UPDATE, 行ロック, READ COMMITTED

設問3〔出庫確定 AP の改修〕について(1),(2)に答えよ。

(1)並列に実行するように変更したが, スループットはさほど向上しなかった。ボトルネックはどこにあるかを説明する次の記述について,(ア)〜(エ) に入れる適切な字句を答えよ。  複数の出庫を並列に処理することになるが, 同じ(ア)と(イ)に対する出庫が複数存在するので, “(ウ)”テーブルの更新で(エ)が発生する。 (ア、イは順不同)

模範解答

ア:倉庫コード イ:部品番号 ウ:在庫 エ:ロックの解放待ち

解説

解答の論理構成

  1. 出庫確定 AP の処理
    【問題文】図4 2-1, 2-2 「“在庫”テーブルの倉庫内在庫数量を更新」「“在庫”テーブルの出庫対象在庫数量を更新」
      → 同一行(キーは「倉庫コード, 部品番号」)を更新する。
  2. ロック仕様
    【問題文】表1 REPEATABLE READ「データ更新時に専有ロックを掛け,トランザクション終了時に解放する。」
      → 更新中の行は他トランザクションから参照も更新もできずロック待ちになる。
  3. 並列化の影響
    出庫を範囲分割して並列実行しても、各プロセスが同じ「倉庫コード」「部品番号」の行を更新するケースが頻発。
    その結果 “在庫” 行の専有ロック解放を待つ ロックの解放待ち が多数発生し、スループットが頭打ちになる。
  4. よって空欄には
    (ア)倉庫コード (イ)部品番号 (ウ)在庫 (エ)ロックの解放待ち
    が入る。

誤りやすいポイント

  • 「範囲指定で出庫番号を分割したから競合しない」と思い込み、キー列の衝突を見落とす。
  • 行ロックは REPEATABLE READ 固有の問題だと誤解し、READ COMMITTED なら解放待ちが起きないと判断する。
  • 在庫テーブルに索引を追加すれば解決するという早合点(索引は探索効率でありロック待ちとは別問題)。

FAQ

Q: UPDATE が 2 回(2-1, 2-2)あるのに 1 行ロックで済むのですか?
A: はい。同一トランザクション内で同じ行を連続更新しても、最初の UPDATE で掛けた専有ロックが COMMIT まで保持されます。追加の UPDATE は既に自トランザクションのロック下にあるため新たなロック待ちは発生しません。
Q: READ COMMITTED に変更すればスループットは上がりますか?
A: 今回は出庫確定 AP を REPEATABLE READ で動かす設計です。READ COMMITTED でも更新行への専有ロックはトランザクション終了時まで保持されるため、同じ行を競合更新する限り根本的なボトルネックは解消されません。

関連キーワード: 排他制御, 行ロック, ロック待ち, 並列処理, ボトルネック

設問3〔出庫確定 AP の改修〕について(1),(2)に答えよ。

(2)(1)のボトルネックを解消するためには出庫確定 AP をどのように変更する必要があるかを説明する次の記述について,(オ)〜(ケ)に入れる適切な字句を答えよ。  出庫番号ではなく,(オ)と(カ)の組合せの値の範囲指定で各プロセスに配分するように変更する。 また, 図4の1で, 出庫番号の昇順ではなく,(オ)と(カ)の昇順に処理を行うように変更する。 “(キ)”テーブルの“(オ)”列と“(カ)”列に,複数列索引を定義しておく。  なお,この索引を定義していない場合, 自プロセスの対象行かを判定するための参照が(ク)となるので,他プロセスが(ケ)した行を参照しようとしてロックの解放待ちとなり, 別のボトルネックが生じる。(オ、カは順不同)

模範解答

オ:出庫元倉庫コード カ:部品番号 キ:出庫 ク:テーブルスキャン ケ:更新 又は 専有ロック

解説

解答の論理構成

  1. 更新競合の原因
    出庫確定 AP は図4で「倉庫内在庫数量」「出庫対象在庫数量」を更新します。これらの更新条件は〈倉庫コード=出庫元倉庫コード〉かつ〈部品番号〉です。よって同じ倉庫・部品を別プロセスが同時に扱えば、在庫行に対する専有ロック競合が起こります。
  2. 適切な分割キー
    競合を無くすには「同じ在庫行を複数プロセスが更新しない」よう範囲分割します。したがってプロセス配分の主キーは
    • 出庫元倉庫コード(オ)
    • 部品番号(カ)
    の組合せとなります。
  3. 索引の必要性
    問題文(1)のRDBMS仕様より「索引を使わずに…テーブルスキャン…全行がロック対象」と明記されています。複合索引を定義しない場合、各プロセスは自分の担当範囲を判定するために全行を読み、共有ロックであっても他プロセスが取得した専有ロックに衝突して待機します。
  4. ボトルネックの連鎖
    ロック待ちは「他プロセスが更新(ケ)した行」を参照しようとした瞬間に発生します。これが新たなボトルネックになるため、複合索引の作成は必須です。
  5. まとめ
    以上より、空欄は
    オ:出庫元倉庫コード
    カ:部品番号
    キ:出庫
    ク:テーブルスキャン
    ケ:更新 又は 専有ロック
    が正答となります。

誤りやすいポイント

  • 出庫番号で分割しても在庫表を更新する条件列が変わらないことを見落とす。
  • 「参照だけならロック競合しない」と思い込み、テーブルスキャン時の共有ロック増大を軽視する。
  • 索引を作ってもロックそのものが無くなるわけではない事実を混同する。

FAQ

Q: 「出庫先倉庫コード」ではダメなのですか?
A: 在庫の更新条件は「出庫元倉庫コード」と「部品番号」です。出庫先倉庫コードで分割しても同じ倉庫・部品行を複数プロセスが更新する可能性が残り、ロック競合は解消しません。
Q: READ COMMITTED に下げればロック待ちは軽減しますか?
A: 出庫確定 AP は REPEATABLE READ が指定されています。READ COMMITTED に変更しても更新完了までは専有ロックが保持されるため、今回の競合(更新×参照)は依然として発生します。分割キーの見直しが根本解決です。

関連キーワード: 排他ロック, 複合索引, テーブルスキャン, 並列処理
← 前の問題へ次の問題へ →

©︎2025 情報処理技術者試験対策アプリ