データベーススペシャリスト試験 2014年 午後1 問02
データベースアクセスの同時実行制御に関する次の記述を読んで、設問1〜3に答えよ。
ソフトウェア開発会社である K 社は、イントラネットに会議室予約システムを構築し、運用している。
〔会議室予約システムの概要〕
会議室予約システムは、各社員の自席のPC及び会議室に設置されているタブレット端末で利用する。
会議室予約システムには社員番号でログインし、会議室番号、予約日、予約開始時刻、予約終了時刻を指定して会議室予約を行う。 予約開始時刻、予約終了時刻には30分単位の時刻を入力する。 また、会議室番号を指定して予約状況を確認したり、人数、日時を指定して空き会議室を検索したりすることができる。 複数の社員が、同じ会議室に対して重複する日時を指定して予約した場合は、最も早く実行された予約を予約成功とし、その他は予約失敗とする。
〔会議室予約システムのテーブル〕
会議室予約システムの主要なテーブルのテーブル構造、概要は、図1、表1のとおりである。



〔RDBMS のトランザクション制御〕
会議室予約システムで使用する RDBMS のトランザクションの ISOLATION レベルは READ COMMITTED であり、行単位でロックをかける。 データ参照時には共有ロックをかけ、参照終了時に解放する。 データ更新時には専有ロックをかけ、トランザクション終了時に解放する。 専有ロックがかかっている間、他のトランザクションからの対象行の参照、更新は専有ロックの解放待ちとなる。
〔会議室予約システムでの検索〕
会議室予約システムで空き会議室の検索結果一覧を表示する際に必要な情報を得るために実行する SQL文の例を図2に示す。
なお、図2中のホスト変数の hv1 は予約希望日、hv2 は予約希望開始時刻、hv3 は予約希望終了時刻を表す。


〔会議室予約システムでの予約処理〕
会議室予約システムの予約処理内容は、図3のとおりである。
なお、図3中のホスト変数の hv1は指定予約日、hv2 は指定予約開始時刻、hv3は指定予約終了時刻、hv4 は指定会議室番号、hv5 は予約者の社員番号を表す (以降の図5図7でも同様とする)。


〔会議室予約システムでのダブルブッキングの検証〕
会議室予約システムにおいてダブルブッキングが発生した。 K 社ではその原因を突き止めるために当日の状況を基に、次の例を用いて図3の予約処理内容の検証を行った。
(例)
・会議室 123 に対する 2014年4月1日の予約を行う。 その日の予約は終日入っていなかった。
・Aさん,Bさん,Cさん、Dさん,Eさんの5人が、それぞれ次の時間帯を指定した。
Aさん: 11時00分〜12時00分
Bさん: 11時00分〜13時00分
Cさん: 11時30分〜13時00分
Dさん: 9時00分〜11時00分
Eさん: 8時00分〜18時00分
(検証)
5人の予約処理の実行が重ならない場合と、重なった場合について、それぞれ(1) 、(2) で検証した。
(1) Aさん,Bさん,Cさん、Dさん,Eさんの順番で、予約処理の実行が重ならない場合の結果を検証して、表2を作成した。
(2) Aさん,Bさん,Cさん、Dさん,Eさんのうち、2人ずつの全ての組合せに対して、先行、後続を入れ替えて、予約処理の実行が重なった場合の結果を検証して、表3を作成した。 表3では、先行の予約処理が図 3①の処理を実後続の予約処理行した後に、後続の予約処理が図 3①の処理を実行、その後に先行の予約処理が図3②の処理を実行することを想定している。る。
なお、後続の予約処理は、先行の予約処理を追い抜くことはないものとする。


(1) 、(2) の検証から、ダブルブッキングとなる理由を次のように結論付けた。
同じ会議室に対して、予約処理の実行が重なった時に、次の二つの条件が成立する場合にダブルブッキングが発生する。
・(r)が重なる。
・(s)が異なる。
〔会議室予約システムの改良案〕
ダブルブッキングを防ぐために図4 表4の “日別予約管理” テーブルを追加し、予約処理内容を図5のように改良することを検討した。



〔会議室予約システムの改良結果〕
図5の⑤〜7の実行時に、ディスク容量不足などのエラーが発生して、予約処理のトランザクションが中断してしまうと問題が生じることが分かったので、〔会議室予約システムの改良案〕 は不採用とし、“会議室予約” テーブルを図6のように変更した。

会議室予約を行う予約単位をコマと呼び、1コマは30分とする。 図6の “会議室予約” テーブルでは、各コマを0時00分から30分間隔で設定する。 予約受付対象の全てのコマはあらかじめ登録しておく。 該当するコマが予約済みか否かを予約済フラグで識別し、予約済みであれば ‘Y'、予約済みでなければ 'N' とする。 例えば,10時00分〜11時30分を予約済みとする場合、予約開始時刻が 10 時 00 分、10時30分、11時00分の3コマの予約済フラグを 'Y' に更新する。
変更した “会議室予約” テーブルを使用して、予約処理内容を図7のように変更した。
なお、図7中のホスト変数の cnt はコマ数を表す。 また、図7中のユーザ定義関数について次に示す。
・PERIODSTART 関数は、コマの終了時刻を与えて、コマの開始時刻を求めるユーザ定義関数とする。 例えば、11時30分を指定した場合、11 時 00 分が返却される。
・PERIODCOUNT 関数は、開始時刻と終了時刻を与えて、含まれるコマ数を求めるユーザ定義関数とする。 例えば、10時00分と11時30分を指定した場合,3が返却される。
・PERIODNEXT 関数は、指定の時刻とコマ数を与えて、指定の時刻からコマ数だけ後にずらしたコマの開始時刻を求めるユーザ定義関数とする。 例えば、10時00分とコマ数2を指定した場合、11時00分が返却される。

設問1:会議室予約システムについて、(1)〜(4)に答えよ。
(1)図2 中の SQL 文の(a)〜(c)に入れる適切な字句を答えよ。
模範解答
a:NOT EXISTS
b:<
c:>
解説
解答の論理構成
- 検索要件の整理
【問題文】には「複数の社員が、同じ会議室に対して重複する日時を指定して予約した場合は、最も早く実行された予約を予約成功とし、その他は予約失敗とする。」とあります。したがって“空き会議室検索”は重複予約が1件も存在しない会議室のみを抽出する処理です。 - サブクエリの役割
図2の SQL は外側でSELECT * FROM 会議室 X
を行い、内側で相関をとる形です。「対象会議室が重複予約を持たない」ことを保証するため、外側 WHERE 句では“既存予約が存在しない”ことを表す必要があります。つまり (a) はNOT EXISTS
です。 - 重複判定条件
重複(オーバーラップ)は次の条件で判定できます。- 既存予約の開始時刻 < 希望終了時刻
- 既存予約の終了時刻 > 希望開始時刻
いずれか一方が等号の場合、同一コマ境界での「背中合わせ」を許可できます。本問では“30分単位”で区切られており背中合わせは問題ないため、厳密に<
と>
を採用します。よって (b) は<
、(c) は>
となります。
誤りやすいポイント
EXISTS
とNOT EXISTS
の選択を逆にし、空いていない会議室ばかり抽出してしまう。- オーバーラップ条件を
<=
・>=
で書き、前後がぴったり接する予約まで除外してしまう。 BETWEEN :hv2 AND :hv3
を使い、重複判定を1条件で済ませようとしても正しく表現できない。
FAQ
Q:
A: 相関サブクエリで行ごとに判断するためには
NOT INではだめですか?
A: 相関サブクエリで行ごとに判断するためには
NOT EXISTSが最も効率的です。
NOT INだとサブクエリの NULL 取り扱いで漏れが生じる恐れがあります。
Q: 等号を含めるべきケースは?
A: 1分単位・秒単位などで管理し、かつ「開始=終了」の瞬間予約を許可しない運用では
A: 1分単位・秒単位などで管理し、かつ「開始=終了」の瞬間予約を許可しない運用では
<=・
>=に変えることがあります。本システムは “30分単位” かつ背中合わせを許容するため
<・
>で問題ありません。
Q: READ COMMITTED なのに検索だけでロック競合しませんか?
A: 共有ロックは読み取り中のみ保持されるので競合は一時的です。ここでは“空き検索”で更新を伴わないため
A: 共有ロックは読み取り中のみ保持されるので競合は一時的です。ここでは“空き検索”で更新を伴わないため
NOT EXISTS判定自体が同時実行上のボトルネックにはなりにくいです。
関連キーワード: NOT EXISTS, サブクエリ、重複検出、READ COMMITTED, 共有ロック
設問1:会議室予約システムについて、(1)〜(4)に答えよ。
(2)図3 中の②は、行が挿入できないことでダブルブッキングとならないように制御している。 その制御で行が挿入できない理由を30字以内で述べよ。
模範解答
・主キーの値が重複するから
・会議室番号、予約日、予約開始時刻が同じ行が存在するから
解説
解答の論理構成
- 一意制約の確認
- 【問題文】「会議室番号、予約日、予約開始時刻で会議室予約を一意に識別する。」
→ この3列が主キー(もしくは UNIQUE 制約)であると読み取れる。
- 【問題文】「会議室番号、予約日、予約開始時刻で会議室予約を一意に識別する。」
- INSERT 処理②の動作
- 図3②の SQL は
INSERT INTO 会議室予約 (会議室番号、予約日、予約開始時刻、予約終了時刻、社員番号) VALUES(:hv4, :hv1, :hv2, :hv3, :hv5);
- 既に同じ「会議室番号、予約日、予約開始時刻」の行が存在すると、主キー一意性が破られ DB が拒否。
- 図3②の SQL は
- ダブルブッキング抑止との関係
- 条件①で重複チェックをしているが、同時実行で別トランザクションが先に INSERT すると②の直前チェックをすり抜ける可能性がある。
- その場合でも一意制約が最後の砦となり、重複キーエラーで行が挿入できず予約失敗となるためダブルブッキングは防止される。
- 以上より、「主キー重複(重複キー)による一意制約違反」が挿入失敗の直接原因である。
誤りやすいポイント
- 「予約終了時刻」まで含めて重複チェックされると誤解しやすい。実際の主キー列に含まれない。
- ロック待ちやデッドロックが原因だと思い込むケース。あくまで制約違反が直接要因。
- SELECT①が空なら必ず INSERT 成功と決めつけ、同時実行による race condition を見落とす。
FAQ
Q: 主キーに含まれない「予約終了時刻」が違う場合でも INSERT は失敗しますか?
A: はい、主キー列「会議室番号、予約日、予約開始時刻」が同じなら失敗します。予約終了時刻は主キーに含まれないため違いは無関係です。
A: はい、主キー列「会議室番号、予約日、予約開始時刻」が同じなら失敗します。予約終了時刻は主キーに含まれないため違いは無関係です。
Q: READ COMMITTED で共有ロックを使っているのに重複キーが発生するのはなぜ?
A: SELECT① の共有ロックは参照終了時に解放されるため、同時実行中に別トランザクションが INSERT 可能となり、競合が起き得ます。このとき主キー制約が重複を最終的に検知します。
A: SELECT① の共有ロックは参照終了時に解放されるため、同時実行中に別トランザクションが INSERT 可能となり、競合が起き得ます。このとき主キー制約が重複を最終的に検知します。
Q: 一意制約エラーはアプリケーション側でハンドリングすべきですか?
A: はい,INSERT 失敗をトランザクション内で検知し、ロールバックやユーザ通知を行うことで整合性を保ちます。
A: はい,INSERT 失敗をトランザクション内で検知し、ロールバックやユーザ通知を行うことで整合性を保ちます。
関連キーワード: 主キー制約、一意性違反、競合解決、行ロック、同時実行制御
設問1:会議室予約システムについて、(1)〜(4)に答えよ。
(3)表 2 中の(d)〜(i)及び表3中の(j)〜(q)に入れる予約成否、失敗検知箇所を答えよ。なお、予約成否は、表2中の注記の記号で答えること。 失敗検知箇所は、予約成否が×の場合に予約失敗を検知した箇所を図3中の番号で答えること。×でない場合は空欄のままとすること。
模範解答
d:×
e:①
f:○
g:
h:×
i:①
j:×
k:②
l:△
m:
n:○
o:
p:△
q:
解説
解答の論理構成
- 図3①の動作
「データ参照時には共有ロックをかけ、参照終了時に解放する」とあるため、先行・後続の①は互いの予約行を見られず、“空き”と判断し得る。 - 主キー衝突条件
【表1】の「会議室番号、予約日、予約開始時刻で会議室予約を一意に識別する」により、開始時刻が同一なら②実行時に一意制約違反となり「×②」。 - 時間帯の重複判定
重複確認は①で行う。②以降は主キー衝突の有無のみ。よって
• 11時00分〜12時00分 と 11時00分〜13時00分 → 主キー衝突 → (j)×・(k)②
• 11時00分〜12時00分 と 11時30分〜13時00分 → 主キー不衝突 → 両者登録 → (l)△
• 11時00分〜12時00分 と 9時00分〜11時00分 → 時間帯不重複、主キー不衝突 → (n)○
• 11時00分〜12時00分 と 8時00分〜18時00分 → 主キー不衝突だが時間帯重複 → 両者登録 → (p)△ - 単独実行時 (表2)
A 成功後に
• B, C, E は①で重複検知 → ×①
• D は終了時刻=A開始時刻で重複と見なさず → ○ - 以上より【模範解答】が導ける。
誤りやすいポイント
- READ COMMITTED でも「共有ロックは参照終了時に解放」という一文を見落とし、①同士が競合すると誤解する。
- 「終了時刻=他予約の開始時刻」を重複と勘違いし、D さんを失敗だと思い込む。
- 主キーが「開始時刻」であることを忘れ、11時30分開始の C さんと11時00分開始の A さんが同時登録できる事実を見落とす。
- “ダブルブッキング発生=△”と“予約失敗=×”を混同し、②でエラーになるケースを△と書いてしまう。
FAQ
Q: なぜロックレベルを行単位にしてもダブルブッキングが起こるのですか?
A: 図3①の SELECT が取得するのは共有ロックで、既に存在する行にしか掛かりません。未登録行(例: 11時30分開始)はロック対象外なので、先行・後続とも“空き”と判断し、それぞれ②で INSERT してしまいます。
A: 図3①の SELECT が取得するのは共有ロックで、既に存在する行にしか掛かりません。未登録行(例: 11時30分開始)はロック対象外なので、先行・後続とも“空き”と判断し、それぞれ②で INSERT してしまいます。
Q: READ COMMITTED 以外なら防げますか?
A: SERIALIZABLE なら①で取得した範囲ロックにより後続 SELECT はブロックされ、先行が②で INSERT した時点の一貫した状態が保証されるため防げます。ただしスループット低下に注意が必要です。
A: SERIALIZABLE なら①で取得した範囲ロックにより後続 SELECT はブロックされ、先行が②で INSERT した時点の一貫した状態が保証されるため防げます。ただしスループット低下に注意が必要です。
Q: 改良案(図7)はなぜ有効なのですか?
A: 「1コマ30分」を先に登録し、UPDATE で
A: 「1コマ30分」を先に登録し、UPDATE で
予約済フラグ='Y'にする方式に変えたことで、同じコマに対する UPDATE が排他ロックで競合します。これにより時間重複の全てを主キー衝突で捕捉でき、①での範囲検索が不要になります。
関連キーワード: 一意制約、READ COMMITTED, 排他ロック、ファントムリード、コマ更新
設問1:会議室予約システムについて、(1)〜(4)に答えよ。
(4)ダブルブッキングとなる条件の(r)、(s)に入れる適切な字句を答えよ。
模範解答
r:時間帯
s:予約開始時刻
解説
解答の論理構成
- 原文の結論部
同じ会議室に対して、予約処理の実行が重なった時に、次の二つの条件が成立する場合にダブルブッキングが発生する。
・(r)が重なる。
・(s)が異なる。 - 「重なる」対象は何か
- 例では 「11時00分〜12時00分」 と 「11時30分〜13時00分」 など、開始・終了の組で示される“期間”が問題となっている。
- 先行・後続でこの期間が重なった場合にだけ表2・表3で “△(ダブルブッキング発生)” が出現。
- よって (r) は時間の「区間」=「時間帯」。
- 「異なる」対象は何か
- 図3①の SELECT 条件は
すなわち “予約開始時刻” と “予約終了時刻” を比較して重複チェックをする。WHERE 会議室番号 = :hv4 AND 予約日 = :hv1 AND 予約開始時刻 (b) :hv3 AND 予約終了時刻 (c) :hv2
- もし両者の 予約開始時刻 が同一なら行ロック競合により後続がブロックされるが、異なれば「READ COMMITTED+共有ロック即解放」のため互いを検知できない。
- 後続が INSERT を実行した時点で幻読が発生し、ダブルブッキングが確定する。
- よって (s) は「予約開始時刻」。
- 図3①の SELECT 条件は
- 以上より
- (r)=時間帯
- (s)=予約開始時刻
誤りやすいポイント
- 「同じ時間帯なら必ず開始時刻も同じ」と思い込む。30分単位なので“11:00〜12:00”と“11:30〜13:00”のように開始時刻がズレても重複します。
- READ COMMITTED だから安全と勘違いし、幻読のリスクを見落とす。
- (s) に「予約終了時刻」を入れてしまう。終了時刻が同じでも開始時刻がズレていれば SELECT で漏れるケースがある点に注意。
FAQ
Q: なぜ「予約終了時刻」が違ってもダブルブッキングと断定しないのですか?
A: 終了時刻が違っても開始時刻が同じなら行ロックでブロックされるため、後続処理は SELECT の時点で検知できます。問題は開始時刻がズレて SELECT 範囲から漏れるケースです。
A: 終了時刻が違っても開始時刻が同じなら行ロックでブロックされるため、後続処理は SELECT の時点で検知できます。問題は開始時刻がズレて SELECT 範囲から漏れるケースです。
Q: ISOLATION レベルを「SERIALIZABLE」に変えれば解決しますか?
A: はい、幻読を防げるので今回の競合は起こりません。ただし性能面でロック競合が増えるため、問題文ではアプリ側のロジック修正を優先しています。
A: はい、幻読を防げるので今回の競合は起こりません。ただし性能面でロック競合が増えるため、問題文ではアプリ側のロジック修正を優先しています。
Q: 30分単位でコマ分割する方式(図7)のメリットは?
A: 各コマに行ロックを直接かけるため、任意の時間帯を UPDATE だけで確実に確保でき、重複チェックと登録を一体化できます。複雑な SELECT 条件が不要になり、幻読を根本的に排除できます。
A: 各コマに行ロックを直接かけるため、任意の時間帯を UPDATE だけで確実に確保でき、重複チェックと登録を一体化できます。複雑な SELECT 条件が不要になり、幻読を根本的に排除できます。
関連キーワード: 幻読、排他制御、行ロック、READ COMMITTED, 時間帯重複
設問2:〔会議室予約システムの改良案〕 について、(1)〜(3)に答えよ。
(1)同じ日に、同じ会議室に対して予約が集中する状況を想定すると、図5 中②でコミットを行わない場合、スループットが低下する。 その原因となる処理を図5中の番号で答えよ。また、原因を25字以内で述べよ。
模範解答
処理番号:①
原因:多数の専有ロックの解放待ちが発生する。
解説
解答の論理構成
- 図5の流れを確認
- 「① 予約処理中フラグをUPDATE文で ‘Y’ に更新する」
- 「② コミットする」
- RDBMS のロック仕様
- 「データ更新時には専有ロックをかけ、トランザクション終了時に解放する」
- 「専有ロックがかかっている間、他のトランザクションからの対象行の参照、更新は専有ロックの解放待ちとなる」
- コミット省略時の影響
- ②を実行しないとトランザクションが終了しない
- よって①で更新した“日別予約管理”の行は専有ロック状態のまま
- 同時アクセスが集中する条件
- 設問が示す「同じ日に、同じ会議室に対して予約が集中」すると、多数のトランザクションが同じ行を読もうとする
- 結果
- 先行トランザクションがコミットするまで後続はロック待ち
- CPU・I/O が遊んでしまいスループットが低下
- よって処理番号は「①」、原因は「多数の専有ロックの解放待ちが発生する」となる。
誤りやすいポイント
- 「図5では②がコミットだから①が原因では?」と逆に考えてしまう
→ コミットを省く条件下では①がロック保持元になる点に注意。 - READ COMMITTED だから参照はブロックされないと思い込む
→ 専有ロック中は参照も待たされる仕様が明示されている。 - “日別予約管理”を読み取り専用だと誤認
→ 実際には①で更新しているためロックが掛かる。
FAQ
Q: READ COMMITTED でも共有ロックはすぐ解放されるのでは?
A: 共有ロックは参照終了時に解放されますが、①は更新なので専有ロックとなり、コミットしない限り解放されません。
A: 共有ロックは参照終了時に解放されますが、①は更新なので専有ロックとなり、コミットしない限り解放されません。
Q: 行ロックだから競合は少ないのでは?
A: 集中する条件では全員が同じ会議室番号・予約日を更新するため、狙う行は1行。行ロックでも競合は激しくなります。
A: 集中する条件では全員が同じ会議室番号・予約日を更新するため、狙う行は1行。行ロックでも競合は激しくなります。
Q: 専有ロック待ち中のトランザクションはタイムアウトしますか?
A: 多くの RDBMS では待機し続けます(設定によってはタイムアウト可)。問題文では待ち続ける前提です。
A: 多くの RDBMS では待機し続けます(設定によってはタイムアウト可)。問題文では待ち続ける前提です。
関連キーワード: 専有ロック、行ロック、コミット、スループット、トランザクション制御
設問2:〔会議室予約システムの改良案〕 について、(1)〜(3)に答えよ。
(2)図5 中の ④において、⑧に進む処理は、速やかに予約失敗を検知するために行っている。この処理はどのような状況を想定して行っているか。 20字以内で述べよ。
模範解答
予約対象に予約が入っている状況
解説
解答の論理構成
- 図5①で
予約処理中フラグ = 'N'
を'Y'
に変えられなかった場合は、同一キーが既に処理中であることを示す。
【問題文引用】「①で予約処理中フラグを更新できておらず…」 - その状態で図5③の検索結果に行が存在すると、希望時間帯へ既に別予約が入っている。
【問題文引用】「③で結果行がある場合…予約失敗として⑧に進む。」 - したがって④では「同じ会議室・同日・重複時間帯に既存予約がある」状況を想定し、速やかに⑧へ遷移して失敗を通知する。
- この想定を20字以内で表すと「予約対象に予約が入っている状況」となる。
誤りやすいポイント
- “予約処理中フラグを更新できない”だけで⑧に進むと誤解する。③の検索結果も要確認。
- 「ダブルブッキング発生時」と書くと時間帯重複が確定していないケースを含み得るため不適切。
- ④のループ条件と⑧への即時遷移を混同し、リトライの有無を取り違える。
FAQ
Q: ④で⑧へ進むとき、ロック待ちは発生しますか?
A: 図5①の
A: 図5①の
UPDATE … AND 予約処理中フラグ = 'N'が失敗しているため行ロックは取得しておらず、ただちに失敗通知へ進むのでロック待ちは発生しません。
Q: ③で結果行がないのに④で⑧へ進むケースはありますか?
A: ありません。④のフローは “③で結果行がある” ことを前提にしています。
A: ありません。④のフローは “③で結果行がある” ことを前提にしています。
Q: “予約処理中フラグ” を使う方式は確実にダブルブッキングを防げますか?
A: ⑤〜⑦でエラー中断時に
A: ⑤〜⑦でエラー中断時に
'Y'が残留する問題があるため、本問では不採用となりました。
関連キーワード: 排他制御、行ロック、楽観的同時実行制御、予約テーブル、競合検知
設問2:〔会議室予約システムの改良案〕 について、(1)〜(3)に答えよ。
(3)〔会議室予約システムの改良結果〕 で述べている 〔会議室予約システムの改良案〕で生じる問題について、どのテーブルがどのような状態になるかを40字以内で述べよ。 また、それによって引き起こされる問題を30字以内で述べよ。
模範解答
状態:“日別予約管理”テーブルの予約処理中フラグが'Y'のままとなる。
問題:その日付、その会議室を誰も予約できなくなる。
解説
解答の論理構成
- 図5①の更新
UPDATE 日別予約管理 SET 予約処理中フラグ = 'Y'
で対象行を占有。 - 図5②でコミット
ここで‘Y’が確定する。 - 図5⑤〜⑦の途中エラー想定
【問題文】「ディスク容量不足などのエラーが発生して、予約処理のトランザクションが中断」と記載。 - フラグ復旧漏れ
エラーにより図5⑥のUPDATE … 'N'
が実行されず、フラグは‘Y’のまま。 - 影響
後続予約は図5①の… 予約処理中フラグ = 'N'
条件で更新不可となり、「その日付、その会議室」を誰も予約できない。
誤りやすいポイント
- トランザクションは②で一度コミット済みなので、後続ロールバックでは‘Y’を戻せない事実を見落とす。
- “会議室予約”テーブルの行ロックを考慮し、フラグ残留問題と混同する。
- “ディスク容量不足”=ロールバックと決め付け、実際には途中で異常終了するシナリオを誤読する。
FAQ
Q: なぜ②でコミットしているのに再度⑦でコミットが必要なのですか?
A: 一連の予約処理を二段階に分けており、①②は“日別予約管理”の確保、⑤〜⑦は実際の予約登録を担うためです。確保後に再度トランザクションを開始し、登録完了時に⑦で確定します。
A: 一連の予約処理を二段階に分けており、①②は“日別予約管理”の確保、⑤〜⑦は実際の予約登録を担うためです。確保後に再度トランザクションを開始し、登録完了時に⑦で確定します。
Q: 途中でフラグを‘N’に戻す他の方法はありますか?
A: タイムアウト検知やバッチでの一括リセットが考えられますが、即時性がなく二重予約を防げません。根本解決には図7のような行ロック方式へ設計変更する方が安全です。
A: タイムアウト検知やバッチでの一括リセットが考えられますが、即時性がなく二重予約を防げません。根本解決には図7のような行ロック方式へ設計変更する方が安全です。
Q: READ COMMITTED でも同時実行制御は十分では?
A: 図5案ではアプリケーションレベルのフラグ管理に依存しており,RDBMSの行ロックとは別に“フラグ残留”という論理的な不整合が発生します。Isolation Level だけでは解決できません。
A: 図5案ではアプリケーションレベルのフラグ管理に依存しており,RDBMSの行ロックとは別に“フラグ残留”という論理的な不整合が発生します。Isolation Level だけでは解決できません。
関連キーワード: トランザクション制御、コミット、ロールバック、排他制御、資源ロック
設問3:〔会議室予約システムの改良結果〕 について、(1)、(2)に答えよ。
(1)図7中の(t)に入れる適切な字句を答えよ。
模範解答
t:COUNT(*)
解説
解答の論理構成
- 図7①のSQLを確認
引用:「GROUP BY 会議室番号 HAVING (t) = PERIODCOUNT(:hv2, :hv3)
」 - 比較対象の右辺
引用:「PERIODCOUNT 関数は、開始時刻と終了時刻を与えて、含まれるコマ数を求める
」
右辺は「必要コマ数」。 - 左辺で求めたい値
予約可能な空きコマを抽出するWHERE … 予約済フラグ = 'N'
で得られた「空きコマ行数」をカウントする必要がある。 - 行数を返す適切な集計関数
SQL標準で行数を返す関数はCOUNT(*)
のみ。 - よって
(t)
はCOUNT(*)
と決定。
誤りやすいポイント
SUM(予約済フラグ)
など列を指定する集計関数を入れると、HAVING
で数値比較できても「空きコマ数」には一致しません。COUNT(予約開始時刻)
としても多くの場合動作しますが、空値が混入すると行数がずれるため安全策としてCOUNT(*)
を選ぶ必要があります。HAVING
はWHERE
の後に集計結果を絞り込む節です。WHERE
にCOUNT(*)
を入れると文法エラーになります。
FAQ
Q: なぜ
A:
MAXや
MINではだめなのですか?
A:
MAXや
MINが返すのは列値の最大・最小であり、行数とは無関係です。必要コマ数と比較しても意味がありません。
Q:
A: 多くのRDBMSで結果は同じですが、問題文に列名が指定されていないため、慣例的に行数を数える
COUNT(1)と
COUNT(*)の違いは?
A: 多くのRDBMSで結果は同じですが、問題文に列名が指定されていないため、慣例的に行数を数える
COUNT(*)を使うのが適切です。
Q:
A:
HAVINGではなく
WHEREで比較してはいけませんか?
A:
WHERE句は集計前に行を絞り込む節なので集計関数は使えません。集計結果を条件にする場合は
HAVINGを用います。
関連キーワード: GROUP BY, HAVING, 集計関数、トランザクション制御、排他制御
設問3:〔会議室予約システムの改良結果〕 について、(1)、(2)に答えよ。
(2)図7中の②において、更新がなくて予約失敗となるのはどのような状況か。 40字以内で述べよ。
模範解答
①の終了後、②の終了までの間に、他の予約処理が範囲内のコマに予約を入れた。
解説
解答の論理構成
- 図7①
SELECT ... 予約済フラグ = 'N' ... HAVING (t) = PERIODCOUNT(:hv2, :hv3)
で重複がないことを確認します。SELECT 終了時点で共有ロックは解放されます(〔RDBMS のトランザクション制御〕「データ参照時には共有ロックをかけ、参照終了時に解放する。」)。 - 図7②
UPDATE ... SET 予約済フラグ = 'Y' ... WHERE ... 予約済フラグ = 'N'
を対象コマ数分繰り返します。もし1回でも “更新行がなかった” 場合にロールバックし予約失敗になります(図7②)。 - 競合シナリオ
①が終わり共有ロックが外れた隙に、別の予約処理が同一コマを予約済フラグ = 'Y'
に変更すると、②のWHERE ... 予約済フラグ = 'N'
条件に合致せず更新0件になります。 - 結論
「①の終了後、②の終了までの間に、他の予約処理が範囲内のコマに予約を入れた」ときに更新0件 → 予約失敗となります。
誤りやすいポイント
- READ COMMITTED では共有ロックはSELECT終了後すぐ外れる点を忘れ、ロックでブロックされると誤解する。
- ②は “全部の更新が成功したか” を見るループであり、1コマでも更新0件なら即ロールバックする仕様を見落とす。
PERIODCOUNT
やPERIODNEXT
の処理ロジックに意識が向きすぎ、ロックタイミングの問題を見逃す。
FAQ
Q: READ COMMITTED 以外のISOLATIONレベルなら防げますか?
A: 例えば SERIALIZABLE にすればダブルブッキングは防げますが、ロック待ち増加で性能が劣化するため、本システムではアプリ側で制御しています。
A: 例えば SERIALIZABLE にすればダブルブッキングは防げますが、ロック待ち増加で性能が劣化するため、本システムではアプリ側で制御しています。
Q: コマ単位方式にしたのにまだダブルブッキングが起こるのですか?
A: 仕様上、②で更新0件になるとロールバックして予約失敗となるのでダブルブッキング自体は起きません。ただし「予約しようとしたが他トランザクションに先を越される」ケースは発生します。
A: 仕様上、②で更新0件になるとロールバックして予約失敗となるのでダブルブッキング自体は起きません。ただし「予約しようとしたが他トランザクションに先を越される」ケースは発生します。
関連キーワード: READ COMMITTED, 行ロック、共有ロック、排他更新、トランザクション競合
