データベーススペシャリスト 2022年 午後1 問03
データベースの実装と性能に関する次の記述を読んで、設問に答えよ。
事務用品を関東地方で販売するC社は、販売管理システム (以下、システムという)にRDBMSを用いている。
〔RDBMSの仕様〕
1.表領域
(1) テーブル及び索引のストレージ上の物理的な格納場所を、表領域という。
(2) RDBMSとストレージとの間の入出力単位を、ページという。同じページに、異なるテーブルの行が格納されることはない。
2.再編成、行の挿入
(1) テーブルを再編成することで、行を主キー順に物理的に並び替えることができる。また、再編成するとき、テーブルに空き領域の割合(既定値は30%)を指定した場合、各ページ中に空き領域を予約することができる。
(2) INSERT 文で行を挿入するとき、RDBMSは、主キー値の並びの中で、挿入行のキー値に近い行が格納されているページを探し、空き領域があればそのページに、なければ表領域の最後のページに格納する。 最後のページに空き領域がなければ、新しいページを表領域の最後に追加し、格納する。
〔業務の概要〕
1.顧客、商品、倉庫
(1) 顧客は,C社の代理店、量販店などで、顧客コードで識別する。顧客にはC社から商品を届ける複数の発送先があり、顧客コードと発送先番号で識別する。
(2) 商品は、商品コードで識別する。
(3) 倉庫は,1か所である。 倉庫には複数の棚があり、一連の棚番号で識別する。商品の容積及び売行きによって、一つの棚に複数種類の商品を保管することも、同じ商品を複数の棚に保管することもある。
2.注文の入力、注文登録、在庫引当、出庫指示、出庫の業務の流れ
(1) 顧客は,C社が用意した画面から注文を希望納品日、発送先ごとに入力し、C社のEDIシステムに蓄える。 注文は、単調に増加する注文番号で識別する。注文する商品の入力順は自由で、入力後に商品の削除も同じ商品の追加もできる。
(2) C社は、毎日定刻 (9時と14時)に注文を締める。 EDIシステムに蓄えた注文をバッチ処理でシステムに登録後、在庫を引き当てる。
(3) 出庫指示書は、当日が希望納品日である注文ごとに作成し、倉庫の出庫担当者(以下、ピッカーという)を決めて、作業開始の予定時刻までにピッカーの携帯端末に送信する。携帯端末は、棚及び商品のバーコードをスキャンする都度、システム中のオンラインプログラムに電文を送信する。
(4) 出庫は、ピッカーが出庫指示書の指示に基づいて1件の注文ごとに行う。
① 棚の通路の入口で、携帯端末から出庫開始時刻を伝える電文を送信する。
② 棚番号の順に進みながら、指示された棚から指示された商品を出庫する。
③ 商品を出庫する都度、携帯端末で棚及び商品のバーコードをスキャンし、商品を台車に積む。 ただし、一つの棚から商品を同時に出庫できるのは1人だけである。また、順路は1方向であるが、通路は追い越しができる。
④ 台車に積んだ全ての商品を、指定された段ボール箱に入れて梱包する。
⑤ 別の携帯端末で印刷したラベルを箱に貼り、ラベルのバーコードをスキャンした後、梱包した箱を出荷担当者に渡すことで1件の注文の出庫が完了する。
〔システムの主なテーブル〕
システムの主なテーブルのテーブル構造を図1に、主な列の意味 制約を表1に示す。主キーにはテーブル構造に記載した列の並び順で主索引が定義されている。



〔システムの注文に関する主な処理〕
注文登録、在庫引当、出庫指示の各処理をバッチジョブで順に実行する。出庫実績処理は、携帯端末から電文を受信するオンラインプログラムで実行する。 バッチ及びオンラインの処理のプログラムの主な内容を、表2に示す。

〔ピーク日の状況と対策会議〕
注文量が特に増えたピーク日に、朝のバッチ処理が遅延し、出庫作業も遅延する事態が発生した。そこで、関係者が緊急に招集されて会議を開き、次のように情報を収集し、対策を検討した。
1.システム資源の性能に関する基本情報
次の情報から特定のシステム資源に致命的なボトルネックはないと判断した。
(1) ページングは起きておらず、CPU使用率は25%程度であった。
(2) バッファヒット率は95%以上で高く、ストレージの入出力処理能力 (IOPS,帯域幅)には十分に余裕があった。
(3) ロック待ちによる大きな遅延は起きていなかった。
2.再編成の要否
アクセスが多かったのは “注文明細” テーブルであった。 この1年ほど行の削除は行われず、再編成も行っていないことから、時間が掛かる行の削除を行わず、直ちに再編成だけを行うことが提案されたが、この提案を採用しなかった。なぜならば、当該テーブルへの行の挿入では予約された空き領域が使われないこと、かつ空き領域の割合が既定値だったことで、割り当てたストレージが満杯になるリスクがあると考えられたからである。
3.バッチ処理のジョブの多重化
バッチ処理のスループット向上のために、ジョブを注文番号の範囲で分割し、多重で実行することが提案されたが、デッドロックが起きるリスクがあると考えられた。そこで、どの処理とどの処理との間で、どのテーブルでデッドロックが起きるリスクがあるか、表3のように整理し、対策を検討した。
4.出庫作業の遅延原因の分析
出庫作業の現場の声を聞いたところ、特定の棚にピッカーが集中し、棚の前で待ちが発生したらしいことが分かった。 そこで、棚の前での待ち時間と棚から商品を取り出す時間の和である出庫間隔時間を分析した。 出庫間隔時間は、ピッカーが出庫指示書の1番目の商品を出庫する場合では当該注文の出庫開始時刻からの時間,2番目以降の商品の出庫の場合では一つ前の商品の出庫時刻からの時間である。出庫間隔時間が長かった棚と商品が何かを調べたSQL文の例を表4に、このときの棚と商品の配置、及びピッカーの順路を図2に示す。


表4中の(x)に、B. 出庫番号、A. ピッカーID, B. 棚番号のいずれか一つを指定することが考えられた。 分析の目的が、特定の棚の前で長い待ちが発生していたことを実証することだった場合、
(x)に(あ)を指定すると、棚の前での待ち時間を含むが、商品の梱包及び出荷担当者への受渡しに掛かった時間が含まれてしまう。(い)を指定すると、棚の前での待ち時間が含まれないので、分析の目的を達成できない。
分析の結果、棚3番の売行きの良い商品S3(商品コード)の出庫で長い待ちが発生したことが分かった。 そこで、出庫作業の順路の方向を変えない条件で、多くのピッカーが同じ棚 (ここでは、棚3番)に集中しないように出庫指示を作成する対策が提案された。 しかし、この対策を適用すると、表3中のケース2でデッドロックが起きるリスクがあると予想した。
例えば、あるピッカーに、1番目に棚3番の商品S3を出庫し、2番目に棚6番の商品S6を出庫する指示を作成するとき、別のピッカーには、1番目に棚(う)の商品(え)を出庫し,2番目に棚(お)の商品(か)を出庫する指示を同時に作成する場合である。
設問1:“2. 再編成の要否”について答えよ。
問題文を見る(1)注文登録処理が “注文明細” テーブルに行を挿入するとき、再編成で予約した空き領域が使われないのはなぜか。 行の挿入順に着目し、理由をRDBMSの仕様に基づいて、40字以内で答えよ。
模範解答
・主キーが単調に増加する番号なので過去の注文番号の近くに行を挿入しないから
・主キーの昇順に行を挿入するとき、表領域の最後のページに格納を続けるから
解説
解答の論理構成
- 行の挿入順の事実
- 問題文より「注文は、単調に増加する注文番号で識別する。」
⇒ 注文番号 が主キーの先頭列であり、値は昇順に連続発生。
- 問題文より「注文は、単調に増加する注文番号で識別する。」
- RDBMSの格納アルゴリズム
- 仕様「挿入行のキー値に近い行が格納されているページを探し…空き領域がなければ表領域の最後のページに格納する。」
⇒ 新しい 注文番号 は既存の最大値より大きいので、探索結果は必ず“最後尾ページ”。
- 仕様「挿入行のキー値に近い行が格納されているページを探し…空き領域がなければ表領域の最後のページに格納する。」
- 再編成で確保した空き領域の位置
- 再編成は各ページに「空き領域の割合(既定値は30%)」を作るが、それは過去の注文番号が並ぶ途中ページ。
- 結論導出
- 挿入先が常に最後尾ページで固定されるため、中間ページの空き領域は参照されず、「再編成で予約した空き領域が使われない」。
誤りやすいポイント
- 「空き領域が使われない=再編成は無意味」と断定する。実際は読み込み効率改善など別効果がある。
- ページ単位で異テーブル混在不可(仕様1(2))を忘れ、空き領域は他テーブル挿入に使えると誤解する。
- INSERT がランダムに行われると想定し、途中ページへ挿入されるケースを過大評価する。
FAQ
Q: 再編成で空き領域を0% に設定すれば問題は解決しますか?
A: 挿入先は最終ページ固定なので空き領域割合を変えても効果は限定的です。むしろ途中更新で行長が伸びる場合のページ分割が発生しやすくなります。
A: 挿入先は最終ページ固定なので空き領域割合を変えても効果は限定的です。むしろ途中更新で行長が伸びる場合のページ分割が発生しやすくなります。
Q: 主キーが日付+連番など増分でない場合はどうなりますか?
A: ランダム挿入が増え、途中ページの空き領域を探す機会が増えるため、再編成で確保した空き領域が有効活用されやすくなります。
A: ランダム挿入が増え、途中ページの空き領域を探す機会が増えるため、再編成で確保した空き領域が有効活用されやすくなります。
Q: オンライン再編成を採用すれば空き領域問題は回避できますか?
A: オンライン/オフラインの方式に関係なく空き領域の位置は同じです。回避策はパーティション分割やテーブル拡張領域のチューニングが中心となります。
A: オンライン/オフラインの方式に関係なく空き領域の位置は同じです。回避策はパーティション分割やテーブル拡張領域のチューニングが中心となります。
関連キーワード: 主キー、ページ、空き領域、INSERT, 物理配置
設問1:“2. 再編成の要否”について答えよ。
問題文を見る(2)行の削除を行わず、直ちに再編成だけを行うと、ストレージが満杯になるリスクがあるのはなぜか。 前回の再編成の時期及び空き領域の割合に着目し、理由をRDBMSの仕様に基づいて、40字以内で答えよ。
模範解答
再編成後に追加した各ページで既定の空き領域分のページが増えるから
解説
解答の論理構成
- 前提確認
- 最後の再編成から「この1年ほど」経過しており、その間に大量の INSERT によりページが増加。
- RDBMSの予約空き領域の仕様
- 再編成時に「空き領域の割合(既定値は30%)」をページ内に確保。
- 予約空き領域が利用されない理由
- 挿入時は「空き領域があればそのページに」だが、予約空き領域は使用対象外なので実際には使われず新ページが追加され続ける。
- 今再編成すると…
- 既存ページにも新規ページにも再び30% の未使用領域が生まれ、総ページ数がさらに増加。
- 結論
- 無駄なページ増加により「割り当てたストレージが満杯になるリスク」が発生。
誤りやすいポイント
- 予約空き領域を「将来の INSERT で自動的に使われる」と誤解する。
- 「行の削除を行わず」とあるので空きページが無いと判断しがちだが、実際はページ内に予約空き領域が存在。
- 再編成=圧縮と短絡的に考え、ストレージ節約になると勘違いする。
FAQ
Q: 予約空き領域を後から変更できますか?
A: はい、多くのRDBMSでは再編成時に比率を再指定できます。ただし再編成自体がI/Oコストを伴うため計画的に行う必要があります。
A: はい、多くのRDBMSでは再編成時に比率を再指定できます。ただし再編成自体がI/Oコストを伴うため計画的に行う必要があります。
Q: ページ内の予約空き領域を INSERT が全く使えないのはなぜ?
A: 予約部分は“将来の UPDATE による行拡張”用に確保され、INSERT の空き領域探索対象外となる実装があるためです。
A: 予約部分は“将来の UPDATE による行拡張”用に確保され、INSERT の空き領域探索対象外となる実装があるためです。
Q: 行削除を併せて行えば問題は解決しますか?
A: 削除+再編成でページを詰めれば空き領域確保量を抑えられますが、削除処理自体が長時間かかる点と運用タイミングに注意が必要です。
A: 削除+再編成でページを詰めれば空き領域確保量を抑えられますが、削除処理自体が長時間かかる点と運用タイミングに注意が必要です。
関連キーワード: ページ分割、空き領域予約、再編成、挿入アルゴリズム、ストレージ効率
設問2:“3. バッチ処理のジョブの多重化”について答えよ。
問題文を見る(1)表3中の(a)〜(c)に入れる適切な理由を、それぞれ30字以内で答えよ。ここで、在庫は適正に管理され、欠品はないものとする。
模範解答
a:異なる商品の“在庫”を逆順で更新することがあり得るから
b:“棚別在庫”を常に主キーの順で更新しているから
c:異なるジョブが同じ注文の明細行を更新することはないから
解説
解答の論理構成
-
ケース1(在庫引当×在庫引当、対象:“在庫”)
- 引当処理は【問題文】「“注文明細”をキー順に読み込み、その順で“在庫”を更新」とある。
- ジョブを注文番号範囲で分割すると、各ジョブが異なる“商品コード”の在庫行を別々の順序で更新し得る。
- 更新順序が異なると互いに行ロックを取り合い“逆順”になりデッドロックが発生。
⇒ (a)「異なる商品の“在庫”を逆順で更新することがあり得るから」
-
ケース2(出庫指示×出庫指示、対象:“棚別在庫”)
- 出庫指示処理は【問題文】「“出庫指示”をキー順に読み込み、その順で“棚別在庫”を更新」と明記。
- キー順(=主キーの昇順)で常に同一順序でロック取得するため、同時ジョブ間でロック待ちは発生しても循環待ちは起きない。
⇒ (b)「“棚別在庫”を常に主キーの順で更新しているから」
-
ケース3(在庫引当×出庫指示、対象:“注文明細”)
- 在庫引当は注文状態“0”を“1”に、出庫指示は注文状態“1”を“2”に変更。
- ジョブ分割では注文番号範囲が互いに排他となり、状態値も異なるため「同じ行」を同時にロックする機会が無い。
⇒ (c)「異なるジョブが同じ注文の明細行を更新することはないから」
誤りやすいポイント
- 「キー順読み込み」がそのまま「キー順更新」になると早合点しがち。ケース1は読み込みテーブルと更新テーブルが異なるため順序が保持されない。
- デッドロック=ロック待ちと混同し、単なる待ち時間をリスクと誤認する。
- 注文状態による行排他を見落とし、ケース3でもリスクありと判断してしまう。
FAQ
Q: キー順で読んでも更新対象テーブルが違うと順序は崩れるのですか?
A: はい。在庫引当では読み込み元は“注文明細”、更新先は“在庫”です。読み込んだ明細に含まれる“商品コード”の並びは注文入力順でバラバラなので、各ジョブで“在庫”行に当たる順序が一致しません。
A: はい。在庫引当では読み込み元は“注文明細”、更新先は“在庫”です。読み込んだ明細に含まれる“商品コード”の並びは注文入力順でバラバラなので、各ジョブで“在庫”行に当たる順序が一致しません。
Q: 主キー順で更新していれば必ずデッドロックは防げますか?
A: 同一テーブルを複数ジョブが同じ主キー順(昇順/降順のどちらかで統一)で更新する限り、循環待ちは発生しないためデッドロックは回避できます。
A: 同一テーブルを複数ジョブが同じ主キー順(昇順/降順のどちらかで統一)で更新する限り、循環待ちは発生しないためデッドロックは回避できます。
Q: 状態遷移で排他を避ける設計は汎用的に有効ですか?
A: 注文処理のように一方向のワークフローで行が段階的に処理される場合、有効な手法です。ただし更新漏れやリカバリ時の整合性チェックが必須です。
A: 注文処理のように一方向のワークフローで行が段階的に処理される場合、有効な手法です。ただし更新漏れやリカバリ時の整合性チェックが必須です。
関連キーワード: デッドロック、ロック順序、主キー順更新、バッチ多重化、状態遷移
設問2:“3. バッチ処理のジョブの多重化”について答えよ。
問題文を見る(2)表3中のケース1のリスクを回避するために、注文登録処理又は在庫引当処理のいずれかのプログラムを変更したい。 どちらかの処理を選び、選んだ処理の処理名を答え、プログラムの変更内容を具体的に30字以内で答えよ。ただし、コミット単位とISOLATIONレベルを変更しないこと。
模範解答
処理名:注文登録
変更内容:・“注文明細”に行を商品コードの順に登録する。
・商品コードの順に注文明細番号を付与する。
処理名:在庫引当
変更内容:・“在庫”の行を商品コードの順に更新する。
解説
解答の導き方
結論(解答)
処理名:在庫引当
変更内容:「在庫」の行を商品コードの順に更新する
変更内容:「在庫」の行を商品コードの順に更新する
導き方(段階的に説明します)
-
問題箇所の特定
表3のケース1は、処理が「在庫引当」と「在庫引当」で、対象テーブルが「在庫」、リスクが「ある」と示しています。したがって、並列実行された複数の在庫引当処理同士でデッドロックが発生する事態を防ぐ必要があります。 -
デッドロック発生の原因を問題文から読む
表2にある在庫引当の説明は「注文明細をキー順に読み込み、その順で在庫を更新し、…注文ごとにコミットする」とあります。つまり、各注文ごとに在庫の該当行を順に更新してロックを取得し、注文単位でコミットします。各トランザクションが行ロックを取得する順序が異なると、循環待ち(デッドロック)が起きます。 -
なぜ更新順を統一すれば回避できるか(具体例)
- 例:注文Aは商品X→商品Y、注文Bは商品Y→商品Xの順に注文明細があるとします。
・トランザクションT1(注文A)はまず在庫のXをロックし、その後Yを取得しようとします。
・同時にT2(注文B)はまず在庫のYをロックし、その後Xを取得しようとします。
するとT1はYのロック待ち、T2はXのロック待ちになり、互いに待ち合ってデッドロックが発生します。 - 一方で、すべてのトランザクションが在庫更新を「商品コードの昇順」で行うと、どのトランザクションも同じ総順序でロックを取得します(例えば常にX→Y)。同一の全順序でロックを取る設計では循環待ちは発生しないため、デッドロックを回避できます。
- 例:注文Aは商品X→商品Y、注文Bは商品Y→商品Xの順に注文明細があるとします。
-
なぜ「在庫引当」を変更するのが確実か
- 在庫引当処理は実際に「在庫」行を更新してロックを取得する箇所なので、ここで取得順を明示的に制御すれば確実に全トランザクションのロック順を統一できます。
- 対案として「注文登録」で注文明細を商品コード順に登録し注文明細番号を付与する方法も理論的に有効ですが、それは間接的な対策です。「注文明細をキー順に読み込む」という既存の振る舞いに依存するため、実装の取りこぼしや将来の変更で保証が外れやすく、より侵襲が大きくなります。よって最小の変更で確実な効果を得るには「在庫引当」を変更する方が望ましいです。
-
実装上の注意(コミット単位・分離レベルは変更しない前提)
- 在庫引当処理内で、当該注文の注文明細から対象の「商品コード」を抽出し、商品コードでソートした順に在庫更新(あるいは SELECT … FOR UPDATE を商品コード順で実行)するようにします。
- こうすることで、各注文を処理するトランザクションは常に同じ商品コード順で在庫行に対してロック取得を行い、デッドロックを回避できます。
- コミット単位(注文ごと)と分離レベルは変えないままで構いません。
以上より、解答は上記のとおりです。
誤りやすいポイント
-
注文明細の登録順を変えれば必ず解決すると思い込む
→ 注文登録で注文明細を商品コード順にする案は成り立ちますが、「注文明細番号の付与まで含めて」すべての入力経路で厳密に同じ順序を保証する必要があり、運用・実装の担当範囲が広がるため見落としが起きやすいです。 -
「並べ替え=SQLのORDER BYだけ書けばよい」と考える誤り
→ 単にSELECTでORDER BYしても、その後の更新処理がその順序でロックを取るよう実装されていなければ意味がありません。明示的にソートした順で更新(あるいは SELECT … FOR UPDATE ORDER BY)する必要があります。 -
ストレージの再編成で解決できると誤認すること
→ 物理配置(再編成)はロック取得順そのものを保証しないため、並列更新による循環待ちの根本対策にはなりません。 -
コミット単位や分離レベルを変えて解決しようとする誤り
→ 設問で変更不可なので、その前提を守らないと失点になります。また、これらを変えると業務要件や整合性に影響を与えます。
FAQ
Q: 注文登録を変える案はなぜ不採用にしたほうがいいですか?
A: 技術的には有効ですが、全ての注文明細の付番ルールを変更・保証する必要があり、他システムや将来の変更により保証が崩れるリスクが高く、より侵襲性が大きいためです。一方、在庫引当の変更は更新箇所に限定され確実性が高いです。
A: 技術的には有効ですが、全ての注文明細の付番ルールを変更・保証する必要があり、他システムや将来の変更により保証が崩れるリスクが高く、より侵襲性が大きいためです。一方、在庫引当の変更は更新箇所に限定され確実性が高いです。
Q: 実装例はどうすればよいですか?
A: 在庫引当処理で処理対象の注文明細を取得し、商品コードでソートしてから順に在庫を更新します。SQLであれば SELECT … FOR UPDATE ORDER BY 商品コード を使うか、アプリケーション側で商品コードをソートして逐次更新します。
A: 在庫引当処理で処理対象の注文明細を取得し、商品コードでソートしてから順に在庫を更新します。SQLであれば SELECT … FOR UPDATE ORDER BY 商品コード を使うか、アプリケーション側で商品コードをソートして逐次更新します。
Q: ソートによる性能悪化が心配ですが現実的ですか?
A: ソートのコストは増えますが、デッドロックによるリトライやバッチ遅延の方が大きな影響となるため、許容される場合が多いです。実運用ではソート対象を注文内でユニーク化して更新回数を減らすなどの最適化を検討します。
A: ソートのコストは増えますが、デッドロックによるリトライやバッチ遅延の方が大きな影響となるため、許容される場合が多いです。実運用ではソート対象を注文内でユニーク化して更新回数を減らすなどの最適化を検討します。
関連キーワード: デッドロック、ロック順序、行レベルロック、ソート順序、トランザクション
設問3:“4. 出庫作業の遅延原因の分析”について答えよ。
問題文を見る(1)本文中の(あ)〜(か) に入れる適切な字句を答えよ。
模範解答
あ:A.ピッカーID
い:B.棚番号
う:6番
え:S6
お:3番
か:S3
解説
解答の論理構成
-
(あ) と (い) の選択
- 出庫間隔時間は「ピッカーが出庫指示書の1番目の商品を出庫する場合では当該注文の出庫開始時刻からの時間」と定義されています。
- これを SQL で実装するには PARTITION BY でピッカー単位に区切り、同一ピッカー内で ORDER BY B.出庫時刻 の時系列を作ります。
- よって (あ)=「A.ピッカーID」。
- 逆にB.棚番号 で区切ると棚単位になり、ピッカー間の待ち時間が除外されて分析目的に合いません。(い) はリスク説明用の対比として「B.棚番号」。
-
(う)〜(か) の選択
- 対策案で示された例:
「あるピッカーに、1番目に棚3番の商品S3, 2番目に棚6番の商品S6」
「別のピッカーには、1番目に棚(う)の商品(え)、2番目に棚(お)の商品(か)」 - デッドロックを発生させるにはロック取得順序を逆にする必要があるため、
・(う)=「6番」、(え)=「S6」
・(お)=「3番」、(か)=「S3」。 - これによりピッカーAは【棚3番→棚6番】、ピッカーBは【棚6番→棚3番】で互いのロックを占有し合います。
- 対策案で示された例:
誤りやすいポイント
- PARTITION BY B.棚番号 を選び、棚ごとに区切ってしまう
→ ピッカー待ち時間が含まれず目的不達。 - (う)と(お)を同じ棚番号にしてしまう
→ ロック順序が同一になりデッドロック例にならない。 - デッドロックは更新行単位と誤解
→ 本問は「棚別在庫」行の複合主キー(棚番号+商品コード)で発生する。
FAQ
Q: PARTITION BY A.ピッカーIDでも注文番号を含めた方が安全では?
A: 注文番号を含めると出庫間隔が注文境界で途切れ、ピッカー移動中の待ち時間が分散してしまいます。分析目的は「棚前の滞留」であり、ピッカー単位が最適です。
A: 注文番号を含めると出庫間隔が注文境界で途切れ、ピッカー移動中の待ち時間が分散してしまいます。分析目的は「棚前の滞留」であり、ピッカー単位が最適です。
Q: 棚順固定でもロック順序が変わるのはなぜ?
A: 出庫指示書の生成順序が異なるため、ピッカーAとBで同じ棚を異なる順番で更新し得ます。ロックはSQLの実行順に取得されるのでデッドロックが起こり得ます。
A: 出庫指示書の生成順序が異なるため、ピッカーAとBで同じ棚を異なる順番で更新し得ます。ロックはSQLの実行順に取得されるのでデッドロックが起こり得ます。
Q: 再編成をしない決定とデッドロック対策は無関係?
A: はい、再編成は物理配置・ストレージ空き領域の問題、デッドロックは同時更新時のロック順序問題で、切り分けて対策を検討します。
A: はい、再編成は物理配置・ストレージ空き領域の問題、デッドロックは同時更新時のロック順序問題で、切り分けて対策を検討します。
関連キーワード: LAG関数、ウィンドウ関数、ロック順序、デッドロック
設問3:“4. 出庫作業の遅延原因の分析”について答えよ。
問題文を見る(2)下線の対策を適用した場合、表3中のケース2で起きると予想したデッドロックを回避するために、出庫指示処理のプログラムをどのように変更すべきか。 具体的に40字以内で答えよ。 ただし、コミット単位とISOLATIONレベルを変更しないこと。
模範解答
・“出庫指示”の読み込み順を出庫番号、商品コード、棚番号の順に変更する。
・“棚別在庫”の行を商品コード、棚番号の順に更新する。
解説
解答の導き方
1)問題の出発点と狙いを確認します。表2に「出庫指示をキー順に読み込み、その順で棚別在庫を更新し、注文明細の注文状態を出庫指示済に更新する」とあり、図1の出庫指示の列順は「出庫番号、棚番号、商品コード」です。したがって現状は出庫指示を主キー順(出庫番号→棚番号→商品コード)で読み、その順で棚別在庫の行をロックして更新しています。さらに表2には「注文ごとにコミットし」とあり、コミット単位は注文(出庫)単位であることが明記されています。これらが前提です。
2)なぜデッドロックが発生するかを整理します。複数の出庫指示ジョブが同時に実行されると、各ジョブが棚別在庫の異なる行に対して排他ロックを取得します。このときジョブAが行X→行Yの順に、ジョブBが行Y→行Xの順にロックを取ると、互いに相手のロック解除を待つ循環待ちが発生しデッドロックになります(典型的なロック順序の逆転)。図2を見ると商品S3は棚3と棚202に保管されており、同一商品が複数棚にまたがるため、異なる出庫指示で同じ棚別在庫行群が異なる順序で更新される可能性が高い点が問題を助長します。
3)回避策の原理は単純です。複数トランザクションが同じ種類の行を更新する場合、すべてのトランザクションでロック取得順を同一の総順序に揃えればデッドロックの循環は作られません。したがって出庫指示処理側で「どの順序で棚別在庫の行へ更新処理(=ロック取得)を行うか」を明確に決め、全ジョブでそれを守らせます。
4)実装上の具体的変更は次の2点です(コミット単位とISOLATIONレベルは変更しない条件を満たします)。
- 出庫指示の読み込み順を出庫番号、商品コード、棚番号の順に変更する。これにより1件の出庫(出庫番号)内で商品コードごとにまとまった順序で処理されます(表2の「注文ごとにコミット」方針を維持)。
- 棚別在庫の行を商品コード、棚番号の順に更新する(すなわちその順でロックを取得する)。全ジョブが同じキー列の昇順で更新すればロック取得順が統一され、デッドロックは発生しなくなります。
以上の変更により、読み取り順と更新(ロック取得)順を一致させ、かつコミット単位を変えずにデッドロックを回避できます。
(最終的な操作指示の例)
出庫指示の読み込み:ORDER BY 出庫番号, 商品コード, 棚番号
棚別在庫の更新処理:処理順を 商品コード, 棚番号 の昇順に揃えて実行
棚別在庫の更新処理:処理順を 商品コード, 棚番号 の昇順に揃えて実行
誤りやすいポイント
- 「主キーの順序をそのまま使えば安全」と考える誤り:図1では出庫指示の主キーが出庫番号→棚番号→商品コードなので、そのままでは棚番号優先のロック順となり、異なるジョブ間で順序逆転が起こり得ます。主キー順に拘る必要はなく、全トランザクションで共通のロック順に揃えることが重要です。
- コミット単位やISOLATIONレベルを変更する案に飛びつく誤り:設問でこれらは変更しない条件なので、これらに頼る解答は不適です。
- 更新対象を「棚番号のみ」でソートする提案:ピッカー割当の変更で同一棚を異なる順で扱う可能性があるため、棚番号だけの順序では逆転が残る場合があります。全トランザクションで一意に定まる複合キー(例:商品コード+棚番号)に基づく順序が必要です。
FAQ
Q: なぜ「商品コード、棚番号」の順にするのですか?
A: 図2にあるように同じ商品(例:S3)が複数棚に存在し、異なる出庫で同一商品の複数棚が対象となることがあるためです。行ロック対象を表す識別子に対して辞書順(商品コード→棚番号)のような一意の総順序を決め、全トランザクションでその順にロックを取ればデッドロックの循環が作られません。
A: 図2にあるように同じ商品(例:S3)が複数棚に存在し、異なる出庫で同一商品の複数棚が対象となることがあるためです。行ロック対象を表す識別子に対して辞書順(商品コード→棚番号)のような一意の総順序を決め、全トランザクションでその順にロックを取ればデッドロックの循環が作られません。
Q: 出庫番号を先頭に残す理由は?
A: 表2に「注文ごとにコミットし」とあり、処理は注文(出庫)単位でコミットすることが前提です。出庫番号を先頭に残すことで「1件の出庫内での商品処理順のみを再ソート」する実装にでき、コミット単位を変更せず要件を満たせます。
A: 表2に「注文ごとにコミットし」とあり、処理は注文(出庫)単位でコミットすることが前提です。出庫番号を先頭に残すことで「1件の出庫内での商品処理順のみを再ソート」する実装にでき、コミット単位を変更せず要件を満たせます。
Q: 更新順を変えると性能が落ちませんか?
A: ソート処理の追加負荷は増えますが、設問の資源状況ではページングやCPU過負荷がないため許容されることが多いです(ただし実運用ではソートコストとロック待ち削減のトレードオフを評価してください)。
A: ソート処理の追加負荷は増えますが、設問の資源状況ではページングやCPU過負荷がないため許容されることが多いです(ただし実運用ではソートコストとロック待ち削減のトレードオフを評価してください)。
関連キーワード: デッドロック、ロック取得順、行ロック、トランザクション、ORDER BY




