DBMS - 并行制御: 初心者向けガイド

こんにちは、未来のデータベース魔术師たち!今日は、データベース管理システム(DBMS)における並行制御の世界に足を踏み入れる興奮的な旅を(start an exciting journey into the world of Concurrency Control in Database Management Systems (DBMS))行います。新しいことを学ぶのが不安だと思わないでください;あなたの親切なガイドとして、私はここにいますので、一歩一歩進んでいきましょう。では、コーヒーを一杯取り、一緒に飛び込んでみましょう!

DBMS - Concurrency Control

並行制御とは?

本題に入る前に、まず並行制御とは何についているのかを理解しましょう。忙しいレストランを思い浮かべてください。複数のウェイターが同時に注文を取ったり、料理を提供したりしています。適切な調整がなければ、混乱が生じますよね!同じように、データベースでは複数のユーザーやプロセスが同時にデータにアクセスし、修正を試みるかもしれません。並行制御とは、その混乱を防ぎ、スムーズに進むよう守るヘッドウェイターのようなものです。

それでは、DBMSにおける並行制御の主要な技術を見ていきましょう。

ロックベースプロトコル

ロックの理解

ロックはホテルの部屋のドアにかけられる「お静かに」のサインのようなものです。トランザクションがデータにアクセスする必要があるとき、それにロックをかけ、「ここで作業中だぞ!」と他に伝えます。

ロックの種類

ロックタイプ 説明 使用シーン
シェアロック(S) 複数のトランザクションがデータを読み取ることができる 変更なしでデータを読み取る
独占ロック(X) 1つのトランザクションだけがこのロックを持つことができる データを書き込むか更新する

2段階ロocking(2PL)プロトコル

このプロトコルは、2つの主要なムーブを持つダンスのようなものです。

  1. 成長段階: ロックを取得し、解放しない。
  2. 縮小段階: ロックを解放し、取得しない。

簡単な例を見てみましょう:

BEGIN TRANSACTION;
-- 成長段階
LOCK TABLE users IN EXCLUSIVE MODE;
UPDATE users SET balance = balance - 100 WHERE id = 1;
LOCK TABLE transactions IN EXCLUSIVE MODE;
INSERT INTO transactions (user_id, amount) VALUES (1, -100);
-- 縮小段階
UNLOCK TABLE users;
UNLOCK TABLE transactions;
COMMIT;

この例では、まず必要なテーブルをロックし、操作を行い、コミットする前にロックを解放します。

デッドロック: 失敗したダンス

2人のダンサーがお互いに動きを待っている状態を考えてみてください。那就是デッドロックです!データベースでは、2つのトランザクションがお互いにロックを待っている状態になります。

デッドロックを防ぐために、以下のような技術を使用します:

  1. タイムアウト: トランザクションが長時間待っている場合、ロールバックされます。
  2. デッドロック検出: システムが積極的にデッドロックを探し、解決します。

タイムスタンプベースプロトコル

それでは、タイムスタンプベースプロトコルに切り替えて話を進めましょう。これらは、トランザクションがシステムに入るときに一意のタイムスタンプを持つチケットを渡すようなものです。

基本タイムスタンプ順序(TO)プロトコル

このプロトコルでは、タイムスタンプを使用して競合する操作の順序を決定します。レストランで客が到着した順にサービスを行うのと同じです。

以下がその仕組みです:

  1. 各データアイテムXは2つのタイムスタンプ値を持っています:
  • W-timestamp(X): Xを成功して書き込んだトランザクションの最大タイムスタンプ。
  • R-timestamp(X): Xを成功して読み取ったトランザクションの最大タイムスタンプ。
  1. データアイテムXを読み取るトランザクションTの場合:
  • 如果 TS(T) < W-timestamp(X)、Tは遅すぎるため、中止され、再起動されます。
  • それ以外の場合、TはXを読み取り、R-timestamp(X)をmax(R-timestamp(X), TS(T))に設定します。
  1. データアイテムXに書き込むトランザクションTの場合:
  • 如果 TS(T) < R-timestamp(X) または TS(T) < W-timestamp(X)、Tは遅すぎるため、中止され、再起動されます。
  • それ以外の場合、TはXに書き込み、W-timestamp(X)をTS(T)に設定します。

例を見てみましょう:

class DataItem:
def __init__(self):
self.value = None
self.r_timestamp = 0
self.w_timestamp = 0

def read(transaction, data_item):
if transaction.timestamp < data_item.w_timestamp:
print(f"トランザクション {transaction.id} は読み取るのが遅すぎます。中止します...")
abort(transaction)
else:
print(f"トランザクション {transaction.id} は値を読み取ります: {data_item.value}")
data_item.r_timestamp = max(data_item.r_timestamp, transaction.timestamp)

def write(transaction, data_item, new_value):
if (transaction.timestamp < data_item.r_timestamp or
transaction.timestamp < data_item.w_timestamp):
print(f"トランザクション {transaction.id} は書き込むのが遅すぎます。中止します...")
abort(transaction)
else:
print(f"トランザクション {transaction.id} は値を書き込みます: {new_value}")
data_item.value = new_value
data_item.w_timestamp = transaction.timestamp

def abort(transaction):
print(f"トランザクション {transaction.id} は中止され、再起動されます。")

この例では、タイムスタンプ順序プロトコルに従った基本的な読み取りと書き込み操作を実装しています。システムは操作を許可する前にタイムスタンプをチェックし、それに応じて更新します。

Thomas Writeルール: スマートな最適化

Thomas Writeルールは、レースで速いランナーが遅いランナーを通り越すのと同じです。このルールにより、「遅すぎる」と判断された書き込み操作を無視することができます。

以下がその仕組みです:

如果 TS(T) < W-timestamp(X)、Tを中止する代わりに、この書き込み操作を無視します。これは、書き込まれる値がすでに古いからです。

書き込み関数にThomas Writeルールを追加してみましょう:

def write_with_thomas_rule(transaction, data_item, new_value):
if transaction.timestamp < data_item.r_timestamp:
print(f"トランザクション {transaction.id} は書き込むのが遅すぎます。中止します...")
abort(transaction)
elif transaction.timestamp < data_item.w_timestamp:
print(f"トランザクション {transaction.id} の書き込みはThomas Writeルールにより無視されます。")
else:
print(f"トランザクション {transaction.id} は値を書き込みます: {new_value}")
data_item.value = new_value
data_item.w_timestamp = transaction.timestamp

この最適化により、不要なトランザクションの中止を減少させ、システムの全体性能を向上させることができます。

締め括り

息を吸ってください!今日は多くのことをカバーしました。ロックベースプロトコルからタイムスタンプベースプロトコルまで、並行制御は同時データベース操作の混沌の中で秩序を保つ东西です。交通量の多い交差点で交通警察官として、 everyone gets where they need to go without crashing into each otherようにして確保するのと同じです。

データの世界を探索し続ける中で、より高度な概念や技術に出会うことでしょう。でも今は、並行制御の基本的な概念を掌握した自分を褒めてください!

練習を続け、好奇心を持ち、ハッピーコーディングを!

Credits: Image by storyset