ロックのエスカレーションが必要な理由と、いわゆるロックオーバーヘッドとは何かを簡単に説明できますか?
テーブルを更新して行をロックするときは、この事実を何らかの方法で記録する必要があります。これは行であり、更新されてロックされています。
百万行を更新する場合、これを百万回行う必要があるため、百万のロックを保持するためのスペースがあります。
SQL Serverはロックのリストをメモリに保持しますが、Oracleはテーブルスペースに保持します。
これはおそらく、Oracleが古く(私より古い)、SQLServerがOracleに比べて若いためです。
一時的なリソース(ロックなど)を永続的なストレージに保持することは、設計者の観点からはそれほど明白な解決策ではありません。言及するのは1つだけです。を実行するには、ディスクへの書き込みが必要になる場合がありますSELECT FOR UPDATE
。
オラクルのコア機能は、物事をメモリに保持することがまったく選択肢になかった80年代初頭に開発されました。彼らはどういうわけかディスクスペースを使わなければなりませんでした。
とにかくディスクスペースを使用する場合は、ディスクのどこかにロックを設定する必要がありました。
そして、行自体の中にない場合、どこで行のロックを維持するのですか?
SQL Serverのロックシステムの開発者は、Sybaseと呼ばれるRDBMSの設計を考案したときに、一時的なもの(つまり、ロック)を一時的なストレージ(つまりRAM)に格納することにしました。
ただし、Oracleの設計は常にバランスが取れています。データベースに1,000,000行ある場合は、1,000,000ロック用のストレージスペースがあり、10億行ある場合は、10億ロックを保存できます。
この意味で、SQL Serverの設計には欠陥があります。これは、RAMとHDDのスペースが不均衡である可能性があるためです。16MのRAMと数テラバイトのディスクスペースを簡単に使用できます。そして、あなたの記憶はすべてのロックを保持することはできません。
そのため、ロックカウントが特定の制限に達すると、SQL Serverはロックをエスカレーションすることを決定します。たとえば、データページの10行(10レコードが必要)のロックを保持する代わりに、データページ全体(必要な1レコード)。
一方、Oracleは、行を更新するときに、ロックをデータページに直接書き込むだけです。
これが、Oracleのロックが行レベルである理由です。
Oracleは、常識的な意味でロックを「管理」しません。たとえば、Oracleでロックされたページのリストを取得することはできません。
トランザクションが行を更新する必要がある場合、トランザクションはその行に移動し、ロックされているかどうかを確認します。
そうである場合、どのトランザクションがロックを保持しているかを調べ(この情報はデータページのロック記述子に含まれています)、そのトランザクションの通知キューに追加されます。ロックしているトランザクションが終了すると、元のトランザクションに通知が届き、データがロックされます。
同時実行性の観点からは、ロックのエスカレーションは完全に貧弱な人の解決策です。それは同時実行性に何も追加しません。たとえば、触れていない行をロックすることができます。
もちろん、パフォーマンスの観点からは、メモリ内で実行する方が、ディスク上で実行するよりも高速です。
ただし、Oracleはデータブロックをキャッシュし、上記の実際の操作はとにかくメモリ内で実行されるため、パフォーマンスは同じかそれに近いものになります。