# `MVCC`
```15
~!@// Transaction 1:@!~
  Begin（start_ts = 100）
    < 1, Tom > -> < 1, Jack >
    < 2, Andy > -> < 2, Candy > 
  Commit;（commit_ts = 110）

~!@// Transaction 2:@!~
  Begin（start_ts = 115）
    < 1, Jack > -> < 1, Tim >
    < 4, Tony > -> < 4, Jerry > 
```

------------------------------------------------------------------------------
分散トランザクションの実装で、データの変更がコミットされていない場合、読み取り操作はエラーを返すことを学びました。これは、書き込み操作が他の書き込み操作だけでなく、読み取り操作もブロックすることを意味します。理論上は問題ではないが、高い並行性を持つシステムでは効率が悪くなる可能性があります。特定の行のデータがトランザクション内で変更される場合、その行のデータに対する操作はシリアルになり、パフォーマンスが低下する可能性があります。

上記の問題の解決策として、マルチバージョン並行制御（略してMVCC）と呼ばれるものがあります。

MVCCテクノロジーでは、あるデータオブジェクトを変更または削除したいとき、データベースは既存のデータオブジェクト自体を直接削除または変更せず、新しいバージョンのデータオブジェクトを作成します。このようにすることで、同時に読み取り操作はまだ古いバージョンのデータを読み取ることができ、同時に書き込み操作を行うことができます。このモードの利点は、読み取り操作がもはやブロックされなくなることです; 実際、ロックする必要は全くありません。

分散トランザクションセクションでは、データの変更や削除を行うためにTiKVは実際には追加操作（PUT、DELETE）を行うだけで、元のデータを変更や削除することはしないことがわかりました。そのため、TiKVでは以前のバージョンのデータを持っているので、次の問題は正しいバージョンのデータをどうやって見つけるかということになります。

仮定してみましょう、以下のシナリオです：

現在、2つのトランザクションがあります。トランザクション1は提出され、そのstart_tsは100、commit_tsは110です。トランザクション2は開始されましたが、まだコミットされていません。そのstart_tsは105です。

トランザクション1のワークフロー:

```
Begin（start_ts = 100）
< 1,Tom > -> < 1,Jack >
< 2,Andy > -> < 2, Candy > 
Commit;（commit_ts = 110）
```


トランザクション2のワークフロー:

```
Begin（start_ts = 115）
< 1,Jack > -> < 1,Tim >
< 4,Tony > -> < 4, Jerry >
```


TSOが120になった時点で、key=1、key=2、key=4の値をクエリするためのクエリを実行します。常識的には、MVCCメカニズムがない場合、key=1とkey=4はトランザクション2にあるためエラーやブロックが返され、key=2は値=Candyがクエリ結果として返されるでしょう（なぜならトランザクション1が完了しているからです）。

しかし、MVCCメカニズムを使用すると、タイムスタンプ120の読み取りでは、< 2, Candy > のみでなく、< 1,Jack > と < 4,Tony > も読み取ることができます。なぜなら、トランザクション1がコミットされていないため、コミットされる前の値を読み取ることができるからです。
