# フラッシュバックテーブルとフラッシュバッククエリ

### 概要
+ これらの演習では、フラッシュバックテーブルとフラッシュバッククエリの機能について学習できます。TiDBのMVCCメカニズムのため、GCライフタイムウィンドウ内のTiDBの過去のデータを取得することができます。
+ いくつかのテーブルを作成し、それらに値を挿入します。以降、`FLASHBACK TABLE`ステートメントを使用してそれらを削除および復元することができます。または、`AS OF`節を使用してインラインのフラッシュバッククエリを実行して古いデータを取得することができます。演習のステップを進めるにつれて、GCセーフポイントのコンセプトについてより深く理解することができます。

### 注意
+ いくつかのステップでは、2つの異なるターミナルウィンドウでコマンドを入力する必要があります。2つのターミナルを起動し、演習の間ずっと開いておくと便利でしょう。
+ この演習で利用する、`IP`、`port`、`username`、`password`、`directory`などは、あなたの環境と異なる場合があります。
+ ターミナルウィンドウの"`$`"とはOSプロンプトです。
+ ターミナルウィンドウ内の "`tidb>`" または "`mysql>`" は、SQL コマンドプロンプトです。
+ これらの演習は、ノートパソコンなどの単一のマシン上で実行することができます。

### 前提条件
+ macOSまたはLinuxを使用していること。
+ [lab repository](https://github.com/pingcap/tidb-course-201-lab.git)をクローン済みであること。
+ 演習「テスト用にTiDBクラスタを作成する」を完了していること。

## 演習 1：フラッシュバックテーブル

  <img src="./diagram/2013E031_ja_001_20230404.png" width="60%" align="top"/>

### 概要
+ この演習では、 `FLASHBACK TABLE`ステートメントを使用してテーブルを復元します。

### 所要時間
+ この演習は約10分程度かかります。

### タスク
1. TiDBサーバーに接続します。
2. `FLASHBACK TABLE`のデモスクリプトをレビューします。
3. `FLASHBACK TABLE` ステートメントを使用して、削除されたテーブルを復元します。

### 手順
1. もしTiDB Playgroundユーザーの場合は、`connect-4000.sh`スクリプトを実行し、ユーザーを`root`としてTiDBサーバーに接続します。
   ```
   $ cd tidb-course-201-lab/scripts
   $ ./connect-4000.sh
   ...
   tidb:4000>
   ```

2. デモスクリプト`07-demo-flashback-table.sql`のレビューを行います。

   デモスクリプトの内容を出力して、コメントを通じて各文を理解します。
   ```sql
   SYSTEM cat 07-demo-flashback-table.sql
   ```

   `test.r2`というシンプルなテーブルを作成し、2つの行を挿入します。
   ```
   /* Setup */
   DROP TABLE IF EXISTS test.r1, test.r2;
   CREATE TABLE test.r1(id INT PRIMARY KEY);
   /* Insert values into test.r1 */
   INSERT INTO test.r1 (id)
   VALUES (1);
   INSERT INTO test.r1 (id)
   VALUES (2);
   ```

   テーブル`test.r1`の2つの行を確認します。
   ```
   /* Query A: Verify data in table test.r1, we are expecting COUNT 2 */
   SELECT COUNT(*),
    NOW()
   FROM test.r1;
   ```

   `tikv_gc_safe_point`変数をクエリして、TiDBで保持できる最も古い歴史的データを確認し、`COMMENT`カラムで見つかった値を確認します。
   ```
   /* Query B: Verify the GC safe point */
   SELECT VARIABLE_NAME,
    VARIABLE_VALUE,
    COMMENT
   FROM mysql.tidb
   WHERE variable_name = "tikv_gc_safe_point";
   ```

   テーブル`test.r1`を削除し、再度クエリを実行します。エラーは想定通りです。
   ```
   DROP TABLE test.r1;
   /* Query C: ERROR 1146 is expected */
   SELECT COUNT(*)
   FROM test.r1;
   ```

   過去のバージョンから、テーブル`test.r1`を`test.r2`に復元します。
   ```
   /* Extract the table test.r1 and its rows from previous version to test.r2 within the GC safe-point window */
   FLASHBACK TABLE test.r1 TO r2;
   /* Query D: You can access the dropped table data from test.r2 now */
   SELECT COUNT(*)
   FROM test.r2;
   ```

3. デモスクリプト`07-demo-flashback-table.sql`を実行して、表示された結果を確認します。
   ```sql
   SOURCE 07-demo-flashback-table.sql
   ```
   ```
   tidb:4000> SOURCE 07-demo-flashback-table.sql
   --------------
   DROP TABLE IF EXISTS TEST.R1, TEST.R2
   --------------

   Query OK, 0 rows affected, 2 warnings (0.00 sec)

   --------------
   CREATE TABLE TEST.R1(ID INT PRIMARY KEY)
   --------------

   Query OK, 0 rows affected (0.09 sec)

   --------------
   INSERT INTO TEST.R1 (ID)
   VALUES (1)
   --------------

   Query OK, 1 row affected (0.01 sec)

   --------------
   INSERT INTO TEST.R1 (ID)
   VALUES (2)
   --------------

   Query OK, 1 row affected (0.00 sec)

   --------------
   SELECT COUNT(*),
    NOW()
   FROM TEST.R1
   --------------

   +----------+---------------------+
   | COUNT(*) | NOW()               |
   +----------+---------------------+
   |        2 | 2023-05-19 14:47:22 |
   +----------+---------------------+
   1 row in set (0.00 sec)

   --------------
   SELECT VARIABLE_NAME,
    VARIABLE_VALUE,
    COMMENT
   FROM MYSQL.TIDB
   WHERE VARIABLE_NAME = "tikv_gc_safe_point"
   --------------

   +--------------------+-----------------------------+--------------------------------------------------------------+
   | VARIABLE_NAME      | VARIABLE_VALUE              | COMMENT                                                      |
   +--------------------+-----------------------------+--------------------------------------------------------------+
   | tikv_gc_safe_point | 20230519-14:35:58.911 +0000 | All versions after safe point can be accessed. (DO NOT EDIT) |
   +--------------------+-----------------------------+--------------------------------------------------------------+
   1 row in set (0.00 sec)

   --------------
   DROP TABLE TEST.R1
   --------------

   Query OK, 0 rows affected (0.24 sec)

   --------------
   SELECT COUNT(*)
   FROM TEST.R1
   --------------

   ERROR 1146 (42S02): Table 'test.R1' doesn't exist
   --------------
   FLASHBACK TABLE TEST.R1 TO R2
   --------------

   Query OK, 0 rows affected (0.13 sec)

   --------------
   SELECT COUNT(*)
   FROM TEST.R2
   --------------

   +----------+
   | COUNT(*) |
   +----------+
   |        2 |
   +----------+
   1 row in set (0.00 sec)
   ```

## 演習 2：フラッシュバッククエリ

   <img src="./diagram/2013E032_ja_001_20230404.png" width="60%" align="top"/>

### 概要
+ この演習では、`AS OF`句を使用して、テーブルから過去のデータをクエリします。


### 所要時間
+ この演習は約10分程度かかります。


### タスク
1. フラッシュバッククエリのデモスクリプトを確認します。
2. `AS OF` 句を使用して、フラッシュバッククエリを実行します。


### 手順
1. デモスクリプト`07-demo-flashback-query.sql`のレビューを行います。

   デモスクリプトの内容を出力して、コメントを通じて各ステートメントを理解します。
   ```sql
   SYSTEM cat 07-demo-flashback-query.sql
   ```

   テーブル名`test.fbq`を作成して、1行挿入します。
   ```
   /* Setup */
   DROP TABLE IF EXISTS test.fbq;
   CREATE TABLE test.fbq (id INT PRIMARY KEY);
   /* Insert values into test.fbq */
   INSERT INTO test.fbq (id)
   VALUES (1);
   ```

   既存のデータを確認して、5秒待機してから変更を適用します。
   ```
   /* Query A: Verify the data in table test.fbq, we are expecting id=1 */
   SELECT id,
    'Current Data'
   FROM test.fbq;
   /* Query B: Apply certain waiting, do nothing for 5 seconds */
   SELECT SLEEP(5);
   /* Update the ID column for the only row in test.fbq table to 2 from 1 */
   UPDATE test.fbq
   SET id = 2
   WHERE id = 1;
   ```

   アップデートされた結果を検証して、その状態から3秒前の情報を反映するテーブルから情報を取得します。
   ```
   /* Query C: Verify the data in table test.fbq, we are expecting id=2 */
   SELECT id
   FROM test.fbq;
   /* Query D: Check the data in table test.fbq from 3 seconds ago, we are expecting id=1 instead of 2 */
   SELECT id,
    'Data from the Past'
   FROM test.fbq AS OF TIMESTAMP(CURRENT_TIMESTAMP() - INTERVAL '3' SECOND);
   ```

   デフォルトの履歴データのライフタイム期間が10分であることを確認します。
   ```
   /* Query E: Check the default GC life time window duration, we are expecting 10 minutes and 0 seconds */
   SHOW VARIABLES LIKE 'tidb_gc_life_time';
   ```

   1時間前の状態を反映したテーブルから情報を取得しようとすると、エラーが発生しますが、これは想定通りです。
   ```
   /* Query F: Check the data in table test.fbq beyond the GC safe point window, error code 9006 is expected */
   SELECT id
   FROM test.fbq AS OF TIMESTAMP(CURRENT_TIMESTAMP() - INTERVAL '1' HOUR);
   /* Query G: Confirm the system setting */
   SELECT NOW(),
    VARIABLE_VALUE
   FROM mysql.tidb
   WHERE variable_name = "tikv_gc_safe_point";
   ```

2. デモスクリプト`07-demo-flashback-query.sql`を実行し、表示された結果を確認します。
   ```sql
   SOURCE 07-demo-flashback-query.sql
   ```
   ```
   tidb:4000> SOURCE 07-demo-flashback-query.sql
   --------------
   DROP TABLE IF EXISTS test.fbq
   --------------

   Query OK, 0 rows affected, 1 warning (0.00 sec)

   --------------
   CREATE TABLE test.fbq (id INT PRIMARY KEY)
   --------------

   Query OK, 0 rows affected (0.09 sec)

   --------------
   INSERT INTO test.fbq (id)
   VALUES (1)
   --------------

   Query OK, 1 row affected (0.00 sec)

   --------------
   SELECT id,
    'Current Data'
   FROM test.fbq
   --------------

   +----+--------------+
   | id | Current Data |
   +----+--------------+
   |  1 | Current Data |
   +----+--------------+
   1 row in set (0.00 sec)

   --------------
   SELECT SLEEP(5)
   --------------

   +----------+
   | SLEEP(5) |
   +----------+
   |        0 |
   +----------+
   1 row in set (5.00 sec)

   --------------
   UPDATE test.fbq
   SET id = 2
   WHERE id = 1
   --------------

   Query OK, 1 row affected (0.01 sec)
   Rows matched: 1  Changed: 1  Warnings: 0

   --------------
   SELECT id
   FROM test.fbq
   --------------

   +----+
   | id |
   +----+
   |  2 |
   +----+
   1 row in set (0.00 sec)

   --------------
   SELECT id,
    'Data from the Past'
   FROM test.fbq AS OF TIMESTAMP(CURRENT_TIMESTAMP() - INTERVAL '3' SECOND)
   --------------

   +----+--------------------+
   | id | Data from the Past |
   +----+--------------------+
   |  1 | Data from the Past |
   +----+--------------------+
   1 row in set (0.00 sec)

   --------------
   SHOW VARIABLES LIKE 'tidb_gc_life_time'
   --------------

   +-------------------+-------+
   | Variable_name     | Value |
   +-------------------+-------+
   | tidb_gc_life_time | 10m0s |
   +-------------------+-------+
   1 row in set (0.00 sec)

   --------------
   SELECT id
   FROM test.fbq AS OF TIMESTAMP(CURRENT_TIMESTAMP() - INTERVAL '1' HOUR)
   --------------

   ERROR 9006 (HY000): GC life time is shorter than transaction duration, transaction starts at 2023-05-19 13:50:55 +0000 UTC, GC safe point is 2023-05-19 14:35:58.911 +0000 UTC
   --------------
   SELECT NOW(),
    VARIABLE_VALUE
   FROM mysql.tidb
   WHERE variable_name = "tikv_gc_safe_point"
   --------------

   +---------------------+-----------------------------+
   | NOW()               | VARIABLE_VALUE              |
   +---------------------+-----------------------------+
   | 2023-05-19 14:50:55 | 20230519-14:35:58.911 +0000 |
   +---------------------+-----------------------------+
   1 row in set (0.00 sec)
   ```

## まとめ
演習全体に渡って、データのバージョン履歴が保持される期間を決定するシステム変数は`tidb_gc_life_time`で、デフォルト値は10分間です。詳しくは、[TiDBのドキュメント](https://docs.pingcap.com/ja/tidb/stable/system-variables#tidb-gc-life-time-span-class-version-mark-new-in-v5-0-)を参照します。

## 演習終わり
