web-dev-qa-db-ja.com

楽観的ロック対悲観的ロック

楽観的ロックと悲観的ロックの違いを理解しています。どちらを一般的に使用するのか、誰かが私に説明できますか。

この質問に対する答えは、ストアドプロシージャを使用してクエリを実行するかどうかによって変わりますか。

しかし、単に確認するために、楽観的とは「読み取り中にテーブルをロックしない」という意味で、悲観的とは「読み取り中にテーブルをロックする」という意味です。

458
Jason Baker

Optimistic Locking は、レコードを読み、バージョン番号を書き留めて(日付、タイムスタンプ、またはチェックサム/ハッシュを含む)、そのバージョンがハッシュされていないことを確認する方法です。レコードを書き戻す前にtが変更されました。レコードを書き戻すときは、アトミックであることを確認するためにバージョンの更新をフィルタします。 (つまり、バージョンをチェックしてからレコードをディスクに書き込むまでの間には更新されていません)そして1回のヒットでバージョンを更新します。

レコードが汚れている(つまり、あなたのバージョンと異なる)場合は、トランザクションを中止し、ユーザーはそれを再開できます。

この方法は、セッションのためにデータベースへの接続を必ずしも維持する必要がない大容量システムや3層アーキテクチャに最も適しています。この状況では、接続はプールから取得されるため、クライアントはデータベースロックを実際には維持できず、アクセスごとに同じ接続を使用していない可能性があります。

Pessimistic Locking は、レコードが終了するまで、そのレコードを排他的使用のためにロックしたときです。これは楽観的ロックよりもはるかに優れた整合性を持ちますが、 Deadlocks を避けるためにアプリケーションの設計に注意する必要があります。ペシミスティックロックを使用するには、データベースへの直接接続(通常 2層クライアントサーバー アプリケーションの場合のように)、または独立して使用できる外部で利用可能なトランザクションIDが必要です。接続の.

後者の場合は、TxIDを使用してトランザクションを開き、そのIDを使用して再接続します。 DBMSはロックを維持し、TxIDを介してセッションを元に戻すことを可能にします。これが、2フェーズコミットプロトコル( XA または COM + Transactions など)を使用した分散トランザクションの仕組みです。

多くの衝突が予想されない場合は、楽観的ロックが使用されます。通常の操作を実行するのにかかる費用は少なくなりますが、衝突が発生した場合は、トランザクションが中止されたときにそれを解決するためにより高い価格が支払われます。

ペシミスティックロックは、衝突が予想されるときに使用されます。同期に違反するトランザクションは単純にブロックされます。

適切なロックメカニズムを選択するには、読み書きの量を見積もり、それに応じて計画を立てる必要があります。

145
Ilya Kochetov

楽観論は、読んでいる間は何も変わらないと仮定しています。

ペシミスティックは、何かがそれをロックすると仮定しています。

データが完全に読み取られることが重要ではない場合は、楽観的な方法を使用してください。あなたは奇妙な「汚い」読みを得るかもしれません - しかし、それはデッドロックなどを引き起こす可能性がはるかに低いです。

ほとんどのWebアプリケーションはダーティリードで問題ありません - まれに、次のリロードでデータが正確に集計されるわけではありません。

正確なデータ操作のために(多くの金融取引のように)悲観的な方法を使います。示されていない変更なしにデータが正確に読み取られることが重要です。追加のロックオーバーヘッドはその価値があります。

Microsoft SQL Serverはデフォルトでページロックを使用しています。基本的には読んでいる行とその両側です。行ロックはより正確ですが、はるかに遅くなります。読み取り中のデッドロックを回避するために、トランザクションを読み取り専用またはロックなしに設定することをお勧めします。

62
Keith

すでに述べたことに加えて、楽観的ロックは予測可能性を犠牲にして同時実行性を向上させる傾向があると言われるべきです。悲観的ロックは並行性を低下させる傾向がありますが、より予測可能です。

あなたはあなたのお金などを払います

39
skaffman

悲観的ロックがより良い選択である場合、私はもう一つのケースを考えるでしょう。

楽観的ロックでは、データ変更のすべての参加者がこの種のロックの使用に同意する必要があります。しかし、誰かがバージョンカラムを気にせずにデータを変更すると、楽観的ロックの概念全体を損なうことになります。

17
Nikolay

基本的に2つの最も一般的な答えがあります。 最初の 基本的に言う

楽観的ロックでは、セッションのためにデータベースへの接続を必ずしも維持する必要はない3層アーキテクチャが必要です。一方、Pessimistic Lockingは、レコードを終了するまで排他的に使用するためにレコードをロックする場合です。データベースへの直接接続が必要な楽観的ロックよりもはるかに優れた整合性があります。

もう一つの答えは

オプティミスティック(バージョン管理)はロックがないため高速ですが、(悲観的)ロックは競合が多いときによく実行され、作業を破棄して最初からやり直すよりも防ぐことをお勧めします。

または

あなたが稀な衝突をしているとき、楽観的ロッキングは最もよく働きます

このページに掲載されているとおり .

私は、「接続を維持する」ことが「低衝突」とどのように関連しているかを説明するために私の答えを作成しました。

どの戦略があなたにとって最適であるかを理解するためには、あなたのDBが持っている1秒あたりのトランザクション数ではなく、単一トランザクションの期間について考えてください。通常は、トランザクションを開いて操作を実行し、トランザクションを閉じます。これはANSIが念頭に置いていた、ロックを避けるための古典的な短いトランザクションです。しかし、多くのクライアントが同じ部屋/座席を同時に予約するチケット予約システムをどのように実装しますか?

あなたはオファーを閲覧し、利用可能なオプションと現在の価格の多くでフォームに記入してください。アクセスするデータがロックされていないため、フォームに入力して[同意する]ボタンを押すまでの間に無効な価格が入力されている間は無効になります。すべての価格を変更すると、新しい価格で再起動する必要があります。

あなたがそれらを読むとき、代わりにあなたはすべてのオプションをロックすることができました。これは悲観的なシナリオです。あなたはそれがなぜ吸うのかを見ます。あなたのシステムは、単に予約を開始して喫煙する単一の道化師によって停止される可能性があります。彼が終わるまで誰も予約できません。あなたのキャッシュフローはゼロになります。だからこそ、楽観的な予約が実際に使われています。時間がかかりすぎる人は、より高い価格で予約を再開しなければなりません。

この楽観的なアプローチでは、( mine Repeated Read のように)あなたが読んだすべてのデータを記録し、あなたのデータのバージョンと一緒にコミットポイントに到達しなければなりません。 、現在の価格ではありません)。この時点で、ANSIトランザクションが作成され、DBがロックされ、何も変更されていないかどうかがチェックされ、操作がコミットまたは中止されます。 IMO、これは _ mvcc _ の効果的なエミュレーションであり、これはOptimistic CCにも関連しています。また、中止の場合にトランザクションが再開されると仮定します。ここでのトランザクションは人間のユーザの決定を含みます。

私はMVCCを手動で実装する方法を理解することからは程遠いですが、再始動のオプションを持つ長期実行トランザクションが主題を理解するための鍵であると思います。私がどこか間違っていたら私を直しなさい。私の答えは このAlex Kuznecovの章 によって動機づけられました。

9
Little Alien

ほとんどの場合、楽観的ロックはより効率的であり、より高いパフォーマンスを提供します。悲観的ロックと楽観的ロックを選択するときは、次の点を考慮してください。

  • 悲観的ロックは、多数の更新があり、ユーザーが同時にデータを更新しようとする可能性が比較的高い場合に役立ちます。例えば、各操作が一度に大量のレコードを更新でき(銀行が毎月末に各口座に利息を追加する可能性がある)、2つのアプリケーションが同時にそのような操作を実行している場合、それらは競合します。 。

  • 悲観的ロックは、頻繁に更新される小さなテーブルを含むアプリケーションにも適しています。これらのいわゆるホットスポットの場合、競合が発生する可能性が非常に高いため、楽観的ロックは競合するトランザクションをロールバックするための労力を浪費します。

  • 競合が発生する可能性が非常に低い場合、楽観的ロックは便利です。レコードが多くてもユーザーは比較的少なく、更新もほとんどなく、ほとんどの場合読み取り型の操作です。

7
Koenigsegg

楽観的ロックのユースケースの1つは、アプリケーションでデータベースを使用して、スレッド/ホストの1つがタスクを「主張」できるようにすることです。これは私にとって便利なテクニックです。

私が考えられる最良の例は、データベースを使用して実装されたタスクキューで、複数のスレッドが同時にタスクを要求している場合です。タスクのステータスが 'Available'、 'C​​laimed'、 'C​​ompleted'の場合、dbクエリは "Set status = 'Claimed' where status = 'Available'のように言うことができます。最初のスレッド以外はダーティデータのために失敗します。

これは楽観的ロックのみを含むユースケースです。そのため、「あまり衝突が予想されない場合はオプティミスティック・ロックが使用される」と言う代わりに、衝突が予想されるが1つのトランザクションだけを成功させる場合にも使用できます。

2
Charlie Camp