# 演習 4: クエリの最適化

## 概要

この演習では、特定のクエリに対するオプティマイザーの戦略を決定します。クエリがアクセスするテーブルにインデックスを追加し、クエリ実行計画への影響を評価します。特定のクエリのパフォーマンスを向上させます。


> [!TIP]
> 演習環境がデプロイされたら、下のバーの**次のモジュール**をクリックして**モジュール 1**を開始します。

## モジュール 1: データ準備


+ この演習では、次の実験のために実験データをTiDBデータベースにインポートします。universeというデータベースを作成します。


### 手順 1. リモート Linux にログインします

+ ここをクリック - [ターミナル 1](ssh://monitor1-ssh#1) で、ハンズオン演習用に割り当てられた仮想マシンに接続された新しいターミナルを開きます。

+ ログイン後に表示されるバナーは以下のようになります。

    ```output
     ,     #_
    ~\_  ####_        Amazon Linux 2
    ~~  \_#####\
    ~~     \###|      
    ~~       \#/ ___
    ~~       V~' '->
    ~~~         /    A newer version of Amazon Linux is available!
     ~~._.   _/
        _/ _/       Amazon Linux 2023, GA and supported until 2028-03-15.
      _/m/'           https://aws.amazon.com/linux/amazon-linux-2023/
    ```


### 手順 2. TiDBに接続し、`test`データベースを使用


  ```sql
  cd universe/
  ```
 
  ```sql
  mysql -h ${HOST_DB1_PRIVATE_IP} --port 4000 -u root
  ```


  ```sql
  use test;
  ```
  ```output
  Database changed
  ```


### 手順 3. データのインポート


  ```sql
  source universeV2.sql
  ```
 
  ```output
  Query OK, 0 rows affected, 1 warning (2.03 sec)
  ```


### 手順 4. `universe`を現在のデータベースに設定
  ```sql
  use universe;
  ```
  ```output
  Database changed
  ```


### 手順 5. インポートされたデータをチェック


  ```sql
  SHOW TABLES;
  SELECT COUNT(*) FROM stars;
  SELECT COUNT(*) FROM planets;
  SELECT COUNT(*) FROM moons;
  SELECT COUNT(*) FROM planet_categories;
  SELECT COUNT(*) FROM discoveryFacility;
  SELECT COUNT(*) FROM parameterReference;
  SELECT COUNT(*) FROM planetarySystem;
  ```


  ```output
  tidb>show tables;
  +--------------------+
  | Tables_in_universe |
  +--------------------+
  | discoveryFacility  |
  | moons              |
  | parameterReference |
  | planet_categories  |
  | planetarySystem    |
  | planets            |
  | stars              |
  +--------------------+
  7 rows in set (0.00 sec)


  tidb>select count(*) from stars;
  +----------+
  | count(*) |
  +----------+
  |        2 |
  +----------+
  1 row in set (0.00 sec)


  tidb>select count(*) from planets;
  +----------+
  | count(*) |
  +----------+
  |       10 |
  +----------+
  1 row in set (0.00 sec)


  tidb>select count(*) from moons;
  +----------+
  | count(*) |
  +----------+
  |       28 |
  +----------+
  1 row in set (0.00 sec)


  tidb>select count(*) from planet_categories;
  +----------+
  | count(*) |
  +----------+
  |        3 |
  +----------+
  1 row in set (0.00 sec)


  tidb>select count(*) from discoveryFacility;
  +----------+
  | count(*) |
  +----------+
  |       70 |
  +----------+
  1 row in set (0.00 sec)


  tidb>select count(*) from parameterReference;
  +----------+
  | count(*) |
  +----------+
  |     2055 |
  +----------+
  1 row in set (0.00 sec)


  tidb>select count(*) from planetarySystem;
  +----------+
  | count(*) |
  +----------+
  |    34713 |
  +----------+
  1 row in set (0.02 sec)
  ```


## モジュール 2: インデックス戦略


+ このモジュールでは、以下のクエリに対して実行計画の最適化と比較を行います。
   ```sql
  SELECT pl_name, hostname FROM planetarySystem WHERE pl_name='HAT-P-42 b' and hostname='HAT-P-42';
  ```


  ```sql
  SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where hostname='11 Com' AND ref_id=2048;
  ```


  ```sql
  SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where pl_name='11 Com b' AND ref_id=2048;
  ```


  ```sql
  SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where pl_name='11 Com b' AND hostname='11 Com' AND ref_id=2048;
  ```


  ```sql
  SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where pl_name='11 Com b' AND hostname like '11%' AND ref_id=2048;
  ```


  ```sql
  SELECT id, pl_name, hostname FROM planetarySystem WHERE hostname = '11 Com' AND ref_id=2048;
  ```


  ```sql
  SELECT id, pl_name, hostname FROM planetarySystem WHERE id=835868090839969012 OR ref_id=2048;
  ```


### 手順 1. インデックスを追加し、次のクエリの実行計画を確認


  ```sql
  CREATE INDEX idx_pl_name on planetarySystem(pl_name);
  ANALYZE TABLE planetarySystem;
  EXPLAIN SELECT pl_name, hostname FROM planetarySystem WHERE pl_name='HAT-P-42 b' and hostname='HAT-P-42';
  ```
  ```output
  +-------------------------------+---------+-----------+---------------------------------------------------+-----------------------------------------------------+
  | id                            | estRows | task      | access object                                     | operator info                                       |
  +-------------------------------+---------+-----------+---------------------------------------------------+-----------------------------------------------------+
  | IndexLookUp_11                | 0.00    | root      |                                                   |                                                     |
  | ├─IndexRangeScan_8(Build)     | 5.62    | cop[tikv] | table:planetarySystem, index:idx_pl_name(pl_name) | range:["HAT-P-42 b","HAT-P-42 b"], keep order:false |
  | └─Selection_10(Probe)         | 0.00    | cop[tikv] |                                                   | eq(universe.planetarysystem.hostname, "HAT-P-42")   |
  |   └─TableRowIDScan_9          | 5.62    | cop[tikv] | table:planetarySystem                             | keep order:false                                    |
  +-------------------------------+---------+-----------+---------------------------------------------------+-----------------------------------------------------+
  4 rows in set (0.00 sec)
  ```


+ このクエリのアクセス方法は何ですか？
 + 答え: IndexLookUpとIndexRangeScan。
+ オプティマイザーはこのクエリに対してどのくらいのコストを計算しましたか？
 + 答え: 5.62行です。
+ このクエリを解決するためにTiDBがアクセスする必要のあるカラムはどれですか？
 + 答え: `pl_name`と`hostname`カラムです。
+ このアクセス戦略は良いパフォーマンスをもたらしますか？ なぜですか？
 + 答え: 場合によります。IndexLookUpとIndexRangeScanのアクセス方法は、TiDBがキーバリューに基づいて単一の行を選択できないことを示しています。パフォーマンスは、オプティマイザーが使用するキーがわずか数行に一致する場合にのみ良好であると考えられます。
 
  ```sql
  DROP INDEX idx_pl_name ON planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected (0.36 sec)
  ```


### 手順 2. 別のインデックスを追加し、同じクエリの実行計画を確認


+ `planetarySystem`テーブルで、以前の手順で調べたクエリがテーブル行にアクセスせずに実行されるように、適切なカラムにインデックスを付けるカバリングインデックス `idx_pl_name_hostname` を作成します。
   ```sql
  CREATE INDEX idx_pl_name_hostname on planetarySystem(pl_name, hostname);
  ANALYZE TABLE planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected, 1 warning (5.23 sec)
  ```


  ```sql
  EXPLAIN SELECT pl_name, hostname FROM planetarySystem WHERE pl_name='HAT-P-42 b' and hostname='HAT-P-42';
  ```
  ```output
  +------------------------+---------+-----------+----------------------------------------------------------------------+---------------------------------------------------------------------------+
  | id                     | estRows | task      | access object                                                        | operator info                                                             |
  +------------------------+---------+-----------+----------------------------------------------------------------------+---------------------------------------------------------------------------+
  | IndexReader_6          | 5.62    | root      |                                                                      | index:IndexRangeScan_5                                                    |
  | └─IndexRangeScan_5     | 5.62    | cop[tikv] | table:planetarySystem, index:idx_pl_name_hostname(pl_name, hostname) | range:["HAT-P-42 b" "HAT-P-42","HAT-P-42 b" "HAT-P-42"], keep order:false |
  +------------------------+---------+-----------+----------------------------------------------------------------------+---------------------------------------------------------------------------+
  2 rows in set (0.01 sec)
  ```


+ 出力の違いを説明してください。
 + 答え: クエリは今回`idx_pl_name_hostname`インデックスを使用してクエリを解決しており、テーブル行にアクセスする必要がありません。クエリへのアクセス方法は`IndexReader`と`IndexRangeScan`です。
  ```sql
  DROP INDEX idx_pl_name_hostname ON planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected (0.37 sec)
  ```


### 手順 3. インデックスを追加し、次のクエリの実行計画を確認


  ```sql
  CREATE INDEX idx_pl_name_hostname_ref ON planetarySystem(pl_name, hostname, ref_id);
  ANALYZE TABLE planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected, 1 warning (2.88 sec)
  ```


  ```sql
  EXPLAIN SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where hostname='11 Com' AND ref_id=2048;
  ```
  ```output
  +---------------------------+----------+-----------+-----------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | id                        | estRows  | task      | access object         | operator info                                                                                                                           |
  +---------------------------+----------+-----------+-----------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | Projection_4              | 0.00     | root      |                       | universe.planetarysystem.pl_name, universe.planetarysystem.hostname, universe.planetarysystem.sy_snum, universe.planetarysystem.sy_pnum |
  | └─TableReader_7           | 0.00     | root      |                       | data:Selection_6                                                                                                                       |
  |   └─Selection_6           | 0.00     | cop[tikv] |                       | eq(universe.planetarysystem.hostname, "11 Com"), eq(universe.planetarysystem.ref_id, 2048)                                              |
  |     └─TableFullScan_5     | 34713.00 | cop[tikv] | table:planetarySystem | keep order:false                                                                                                                       |
  +---------------------------+----------+-----------+-----------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  4 rowsにセット (0.00 sec)
  ```


+ このクエリのアクセス方法は何ですか？
 + 答え: `TableReader`と`TableFullScan`。
+ インデックス`idx_pl_name_hostname_ref`はこのクエリのパフォーマンス向上に役立ちますか？ なぜですか？
 + 答え: いいえ。これは、インデックス `idx_pl_name_hostname_ref` が `pl_name`、`hostname`、`ref_id` の順序で構成されているためです。そのため、クエリもインデックスと同じ順序、すなわち `pl_name`、`hostname`、`ref_id` で使用する必要があります。


### 手順 4. 次のクエリの実行計画を確認


  ```sql
  EXPLAIN SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where pl_name='11 Com b' AND ref_id=2048;
  ```
  ```output
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | id                              | estRows | task      | access object                                                                    | operator info                                                                                                                          |
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | Projection_4                    | 0.00    | root      |                                                                                 | universe.planetarysystem.pl_name, universe.planetarysystem.hostname, universe.planetarysystem.sy_snum, universe.planetarysystem.sy_pnum |
  | └─IndexLookUp_11                | 0.00    | root      |                                                                                 |                                                                                                                                        |
  |   ├─Selection_10(Build)         | 0.00    | cop[tikv] |                                                                                 | eq(universe.planetarysystem.ref_id, 2048)                                                                                              |
  |   │ └─IndexRangeScan_8          | 5.62    | cop[tikv] | table:planetarySystem, index:idx_pl_name_hostname_ref(pl_name, hostname, ref_id) | range:["11 Com b","11 Com b"], keep order:false                                                                                        |
  |   └─TableRowIDScan_9(Probe)     | 0.00    | cop[tikv] | table:planetarySystem                                                           | keep order:false                                                                                                                       |
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  5 rowsにセット (0.00 sec)
  ```
 
+ このクエリのアクセス方法は何ですか？
 + 答え: `IndexLookUp`と`IndexRangeScan`。
+ オプティマイザーはこのクエリに対してどのくらいのコストを計算しましたか？
 + 答え: 5.62。
+ このクエリを解決するためにTiDBがアクセスする必要のあるカラムはどれですか？
 + 答え: `pl_name`、`hostname`、`sy_snum`、`sy_pnum`、および`ref_id`。
+ インデックス`idx_pl_name_hostname_ref`はこのクエリのパフォーマンス向上に役立ちますか？ なぜですか？
 + 答え: はい。このクエリにはカラム`pl_name`に関連する条件が含まれていますが、インデックス`idx_pl_name_hostname_ref`が使用されます。しかし、カラム`ref_id`に関連する条件はインデックスを使用しません。なぜなら、カラム`hostname`に関連する条件がクエリに現れなかったからです。EXPLAINの出力の3行目、Selectionのセクションから、`ref_id`に関連する条件は`IndexRangeScan`の後に別途完了されることがわかります。


### 手順 5. 次のクエリの実行計画を確認


  ```sql
  EXPLAIN SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where pl_name='11 Com b' AND hostname='11 Com' AND ref_id=2048;
  ```
  ```output
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | id                              | estRows | task      | access object                                                                    | operator info                                                                                                                           |
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | Projection_4                    | 1.00    | root      |                                                                                  | universe.planetarysystem.pl_name, universe.planetarySystem.hostname, universe.planetarySystem.sy_snum, universe.planetarySystem.sy_pnum |
  | └─IndexLookUp_10                | 1.00    | root      |                                                                                  |                                                                                                                                         |
  |   ├─IndexRangeScan_8(Build)     | 1.00    | cop[tikv] | table:planetarySystem, index:idx_pl_name_hostname_ref(pl_name, hostname, ref_id) | range:["11 Com b" "11 Com" 2048,"11 Com b" "11 Com" 2048], keep order:false                                                             |
  |   └─TableRowIDScan_9(Probe)     | 1.00    | cop[tikv] | table:planetarySystem                                                            | keep order:false                                                                                                                        |
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  4 rowsにセット (0.00 sec)
  ```
+ このクエリのアクセス方法は何ですか？
 + 答え: `IndexLookUp`と`IndexRangeScan`。
+ オプティマイザーはこのクエリに対してどのくらいのコストを計算しましたか？
 + 答え: 1.00。
+ このクエリを解決するためにTiDBがアクセスする必要のあるカラムはどれですか？
 + 答え: `pl_name`、`hostname`、`sy_snum`、`sy_pnum`、および`ref_id`。
+ インデックス`idx_pl_name_hostname_ref`はこのクエリのパフォーマンス向上に役立ちますか？ なぜですか？
 + 答え: はい。クエリには`pl_name`、`hostname`、および`ref_id`のカラムが含まれているため、`index idx_pl_name_hostname_ref`が使用されます。


### 手順 6. 次のクエリの実行計画を確認


  ```sql
  EXPLAIN SELECT pl_name, hostname, sy_snum, sy_pnum FROM planetarySystem where pl_name='11 Com b' AND hostname like '11%' AND ref_id=2048;
  ```
  ```output
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | id                              | estRows | task      | access object                                                                    | operator info                                                                                                                           |
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  | Projection_4                    | 0.00    | root      |                                                                                  | universe.planetarysystem.pl_name, universe.planetarysystem.hostname, universe.planetarysystem.sy_snum, universe.planetarysystem.sy_pnum |
  | └─IndexLookUp_11                | 0.00    | root      |                                                                                  |                                                                                                                                         |
  |   ├─Selection_10(Build)         | 0.00    | cop[tikv] |                                                                                  | eq(universe.planetarysystem.ref_id, 2048)                                                                                               |
  |   │ └─IndexRangeScan_8          | 0.00    | cop[tikv] | table:planetarySystem, index:idx_pl_name_hostname_ref(pl_name, hostname, ref_id) | range:["11 Com b" "11","11 Com b" "12"), keep order,false                                                                               |
  |   └─TableRowIDScan_9(Probe)     | 0.00    | cop[tikv] | table:planetarySystem                                                            | keep order:false                                                                                                                        |
  +---------------------------------+---------+-----------+----------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
  5 rowsにセット (0.00 sec)
  ```


+ このクエリのアクセス方法は何ですか？
 + 答え: `IndexLookUp`と`IndexRangeScan`。
+ このクエリを解決するためにTiDBがアクセスする必要のあるカラムはどれですか？
 + 答え: `pl_name`、`hostname`、`sy_snum`、`sy_pnum`、および`ref_id`。
+ インデックス`idx_pl_name_hostname_ref`はこのクエリのパフォーマンス向上に役立ちますか？ なぜですか？
 + 答え: はい。インデックス `idx_pl_name_hostname_ref` 内のカラム `pl_name`、`hostname`、`ref_id` はすべてクエリ内に現れますが、`hostname` カラムに対する条件が等価クエリではなく範囲クエリであるため、インデックスで `ref_id` カラムを使用することはできません。EXPLAIN 出力の3行目、Selection セクションから、`ref_id` に関連する条件が IndexRangeScan の後に個別に完了することが確認できます。


### 手順 7. 次のクエリの実行計画を確認


  ```sql
  EXPLAIN SELECT id, pl_name, hostname FROM planetarySystem WHERE hostname = '11 Com' AND ref_id=2048;
  ```
  ```output
  +---------------------------+----------+-----------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
  | id                        | estRows  | task      | access object                                                                    | operator info                                                                                    |
  +---------------------------+----------+-----------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
  | Projection_4              | 0.00     | root      |                                                                                  | universe.planetarysystem.id, universe.planetarysystem.pl_name, universe.planetarysystem.hostname |
  | └─IndexReader_10          | 0.00     | root      |                                                                                  | index:Selection_9                                                                                |
  |   └─Selection_9           | 0.00     | cop[tikv] |                                                                                  | eq(universe.planetarysystem.hostname, "11 Com"), eq(universe.planetarysystem.ref_id, 2048)       |
  |     └─IndexFullScan_8     | 34713.00 | cop[tikv] | table:planetarySystem, index:idx_pl_name_hostname_ref(pl_name, hostname, ref_id) | keep order:false                                                                                 |
  +---------------------------+----------+-----------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
  4 rowsにセット (0.01 sec)
  ```
+ このクエリのアクセス方法は何ですか？
 + 答え: `IndexReader`と`IndexFullScan`。
+ インデックス`idx_pl_name_hostname_ref`はこのクエリのパフォーマンス向上に役立ちますか？ なぜですか？
 + 答え: はい。インデックス `idx_pl_name_hostname_ref` のカラム `pl_name` はクエリ条件で使用されていませんが、SELECT ステートメントが `id`、`pl_name`、`hostname` のカラムを含んでいるため、これらすべてはインデックス `idx_pl_name_hostname_ref` に含まれていますので、`IndexFullScan` を使用することができます。
+ このアクセス戦略は良いパフォーマンスをもたらしますか？ なぜですか？
 + 答え: おそらくそうではありません。データボリュームが増加するにつれて、`IndexFullScan`がスキャンする必要があるインデックスデータが増加するため、パフォーマンスが低下します。


  ```sql
  DROP INDEX idx_pl_name_hostname_ref ON planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected (0.36 sec)
  ```


### 手順 8. インデックスを追加し、次のクエリの実行計画を確認


+ `planetarySystem`テーブルで、`ref_id`カラムでインデックス`idx_ref_id`を追加します。
   ```sql
  CREATE INDEX idx_ref_id ON planetarySystem(ref_id);
  ANALYZE TABLE planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected, 1 warning (3.26 sec)
  ```
  
  ```sql
  EXPLAIN SELECT id, pl_name, hostname FROM planetarySystem WHERE id=835868090839969012 OR ref_id=2048;
  ```
  ```output
  +----------------------------------+---------+-----------+-------------------------------------------------+--------------------------------------------------------------------------------------------------+
  | id                               | estRows | task      | access object                                   | operator info                                                                                    |
  +----------------------------------+---------+-----------+-------------------------------------------------+--------------------------------------------------------------------------------------------------+
  | Projection_4                     | 17.00   | root      |                                                 | universe.planetarysystem.id, universe.planetarysystem.pl_name, universe.planetarysystem.hostname |
  | └─IndexMerge_11                  | 17.00   | root      |                                                 | type: union                                                                                      |
  |   ├─TableRangeScan_8(Build)      | 1.00    | cop[tikv] | table:planetarySystem                           | range:[835868090839969012,835868090839969012], keep order:false                                  |
  |   ├─IndexRangeScan_9(Build)      | 16.00   | cop[tikv] | table:planetarySystem, index:idx_ref_id(ref_id) | range:[2048,2048], keep order:false                                                              |
  |   └─TableRowIDScan_10(Probe)     | 17.00   | cop[tikv] | table:planetarySystem                           | keep order:false                                                                                 |
  +----------------------------------+---------+-----------+-------------------------------------------------+--------------------------------------------------------------------------------------------------+
  5 rowsにセット (0.00 sec)
  ```
+ このクエリのアクセス方法は何ですか？
 + 答え: `IndexMerge`。
+ このアクセス戦略は良いパフォーマンスをもたらしますか？ なぜですか？
 + 答え: 場合によります。インデックスマージのアクセス戦略は、TiDBがクエリに使用できる複数のインデックスを見つけたことを示しています。ここでは、主キーと`ref_id`インデックスを使用しています。インデックスマージメソッドは複数のレンジスキャンで行を取得し、結果をマージするため、テーブルに高い選択性のインデックスがあればパフォーマンスは良好です。`operator info`のunionエントリが、TiDBがインデックスマージ結合タイプに対してインデックススキャンをどのようにマージするかを示しています。


  ```sql
  DROP INDEX idx_ref_id ON planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected (0.36 sec)
  ```


## モジュール 3: ORDER BY によるインデックス戦略


+ このモジュールでは、以下のクエリを最適化します
 
  ```sql
  SELECT pl_name, hostname, disc_year FROM planetarySystem WHERE hostname='14 Her' ORDER BY disc_year DESC;
  ```


### 手順 1. 次のクエリの実行計画を確認する


  ```sql
  EXPLAIN SELECT pl_name, hostname, disc_year FROM planetarySystem WHERE hostname='14 Her' ORDER BY disc_year DESC;
  ```
  ```output
  +---------------------------+----------+-----------+-----------------------+-------------------------------------------------+
  | id                        | estRows  | task      | access object         | operator info                                   |
  +---------------------------+----------+-----------+-----------------------+-------------------------------------------------+
  | Sort_5                    | 5.81     | root      |                       | universe.planetarysystem.disc_year:desc         |
  | └─TableReader_10          | 5.81     | root      |                       | data:Selection_9                                |
  |   └─Selection_9           | 5.81     | cop[tikv] |                       | eq(universe.planetarysystem.hostname, "14 Her") |
  |     └─TableFullScan_8     | 34713.00 | cop[tikv] | table:planetarySystem | keep order:false                                |
  +---------------------------+----------+-----------+-----------------------+-------------------------------------------------+
  4 rows in set (0.00 sec)
  ```
+ このクエリのアクセスメソッドは何ですか？ 
 + 答え: TableFullScan、Selection、TableReader、Sort。
+ オプティマイザーがこのクエリで使用できるインデックスはどれですか？ 
 + 答え: なし
+ `operator info` 列にはどのような情報が含まれていますか？ 
 + 答え: `eq(universe.planetarysystem.hostname, "14 Her")`: クエリは WHERE 句を使用して出力行をフィルタリングします。`universe.planetarysystem.disc_year:desc`: TiDBはテーブル全体をもう一度通過して、行をソート順に取得する方法を決定する必要があります。ソートは全ての行を反復して、WHERE句に一致する行のソートキーを行のポインターと共に格納することによって行われます。TiDBサーバーはそのキーをソートし、要求された順序で行を取得します。
+ このクエリのパフォーマンスは良いですか？ なぜですか？ 
 + 答え: いいえ。このクエリは完全なテーブルスキャンを必要とし、キーを使用することなく、`disc_year` カラムに対するソートも必要です。ソートは全てのデータを1つのTiDBサーバーにロードしてタスクを完了する必要があります。
+ テーブルの完全なテーブルスキャンを防ぐためにどのような変更を加える必要がありますか？ 
 + 答え: `planetarySystem` テーブルの `hostname` カラムにインデックスを追加する必要があります。


### 手順 2. インデックスを追加し、次のクエリの実行計画を確認する


  ```sql
  ALTER TABLE planetarySystem ADD INDEX idx_hostname(hostname);
  ANALYZE TABLE planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected, 1 warning (3.41 sec)
  ```


  ```sql
  EXPLAIN SELECT pl_name, hostname, disc_year FROM planetarySystem WHERE hostname='14 Her' ORDER BY disc_year DESC;
  ```
  ```output
  +----------------------------------+---------+-----------+-----------------------------------------------------+---------------------------------------------+
  | id                               | estRows | task      | access object                                       | operator info                               |
  +----------------------------------+---------+-----------+-----------------------------------------------------+---------------------------------------------+
  | Sort_5                           | 5.81    | root      |                                                     | universe.planetarysystem.disc_year:desc     |
  | └─IndexLookUp_13                 | 5.81    | root      |                                                     |                                             |
  |   ├─IndexRangeScan_11(Build)     | 5.81    | cop[tikv] | table:planetarySystem, index:idx_hostname(hostname) | range:["14 Her","14 Her"], keep order:false |
  |   └─TableRowIDScan_12(Probe)     | 5.81    | cop[tikv] | table:planetarySystem                               | keep order:false                            |
  +----------------------------------+---------+-----------+-----------------------------------------------------+---------------------------------------------+
  4 rows in set (0.00 sec)
  ```
+ このクエリのアクセスメソッドは何ですか？ 
 + 答え: IndexRangeScan、IndexLookUp、Sort。
+ オプティマイザーが使用するキーはどれですか？ 
 + 答え: `hostname`
+ `operator info` 列にはどのような情報が含まれていますか？ 
 + 答え: `range:["14 Her","14 Her"], keep order:false`; `universe.planetarysystem.disc_year:desc`。
+ 前の手順で実装した変更はクエリのパフォーマンスを改善しますか？ なぜですか？ 
 + 答え: はい。クエリは完全なテーブルスキャンを必要としなくなります。代わりに、`hostname` カラムのインデックスから行を取得するために `IndexRangeScan` と `IndexLookUp` を使用します。さらに、`task: cop[tikv]` の列は、すべてのインデックスフィルタリング操作が TiKV で並行して完了することを示しています。
+ ソートの実行を防ぐためには何をしなければなりませんか？
 + 答え: `planetarySystem` テーブルに `hostname` と `disc_year` カラムを含む複合インデックスを追加する必要があります。`hostname` カラムのインデックスはこの場合必要ありません、なぜなら TiDB はインデックスプレフィックスを使用できるからです。


### 手順 3. インデックスを追加し、次のクエリの実行計画を確認する


+ 前の手順で特定した変更を行い、ソート操作を削除します。
  ```sql
  ALTER TABLE planetarySystem DROP INDEX idx_hostname;
  ALTER TABLE planetarySystem ADD INDEX idx_hostname_disc_year(hostname, disc_year);
  ```
  ```output
  Query OK, 0 rows affected (3.06 sec)
  ```


  ```sql
  EXPLAIN SELECT pl_name, hostname, disc_year FROM planetarySystem WHERE hostname='14 Her' ORDER BY disc_year DESC;
  ```
  ```output
  +----------------------------------+---------+-----------+--------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------+
  | id                               | estRows | task      | access object                                                            | operator info                                                                                           |
  +----------------------------------+---------+-----------+--------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------+
  | Projection_18                    | 5.81    | root      |                                                                          | universe.planetarysystem.pl_name, universe.planetarysystem.hostname, universe.planetarysystem.disc_year |
  | └─IndexLookUp_17                 | 5.81    | root      |                                                                          |                                                                                                         |
  |   ├─IndexRangeScan_15(Build)     | 5.81    | cop[tikv] | table:planetarySystem, index:idx_hostname_disc_year(hostname, disc_year) | range:["14 Her","14 Her"], keep order:true, desc                                                        |
  |   └─TableRowIDScan_16(Probe)     | 5.81    | cop[tikv] | table:planetarySystem                                                    | keep order:false                                                                                        |
  +----------------------------------+---------+-----------+--------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------+
  4 rows in set (0.00 sec)
  ```
+ オプティマイザーが使用するキーはどれですか？ 
 + 答え: 前の手順で追加したキーです。（例の解決策では `idx_hostname_disc_year`）
+ `operator info` 列にはどのような情報が含まれていますか？ 
 + 答え: `range:["14 Her","14 Her"], keep order:true, desc`。
+ この変更はクエリのパフォーマンスを改善しますか？ なぜですか？ 
 + 答え: はい。`hostname` と `disc_year` カラムに複合キーを追加することで、TiDB サーバーでのソートを行う必要がなくなります。
+ インデックス行を見つけた後、主キーのルックアップを必要としないようにするためには何をしなければなりませんか？ 
 + 答え: `planetarySystem` テーブルに `hostname`、`disc_year` と `pl_name` カラムを含む複合インデックスを追加する必要があります。一方で `hostname` と `disc_year` カラムの複合インデックスを削除する必要があります、なぜなら TiDB はインデックスプレフィックスを使用できるからです。


### 手順 4. インデックスを追加し、次のクエリの実行計画を確認する


  ```sql
  ALTER TABLE planetarySystem DROP INDEX idx_hostname_disc_year;
  ALTER TABLE planetarySystem ADD INDEX idx_hostname_disc_year_pl_name(hostname, disc_year, pl_name);
  ```
  ```output
  Query OK, 0 rows affected (0.35 sec)
  ```


  ```sql
  EXPLAIN SELECT pl_name, hostname, disc_year FROM planetarySystem WHERE hostname='14 Her' ORDER BY disc_year DESC;
  ```
  ```output
  +-------------------------+---------+-----------+-------------------------------------------------------------------------------------------+--------------------------------------------------+
  | id                      | estRows | task      | access object                                                                             | operator info                                    |
  +-------------------------+---------+-----------+-------------------------------------------------------------------------------------------+--------------------------------------------------+
  | IndexReader_12          | 5.81    | root      |                                                                                           | index:IndexRangeScan_11                          |
  | └─IndexRangeScan_11     | 5.81    | cop[tikv] | table:planetarySystem, index:idx_hostname_disc_year_pl_name(hostname, disc_year, pl_name) | range:["14 Her","14 Her"], keep order:true, desc |
  +-------------------------+---------+-----------+-------------------------------------------------------------------------------------------+--------------------------------------------------+
  2 rows in set (0.00 sec)
  ```
+ オプティマイザーが使用するキーはどれですか？ 
 + 答え: idx_hostname_disc_year_pl_name
+ `operator info` 列にはどのような情報が含まれていますか？ 
 + 答え: `range:["14 Her","14 Her"], keep order:true, desc`; `index:IndexRangeScan_11`
+ この変更はクエリのパフォーマンスを改善しますか？ なぜですか？ 
 + 答え: はい。クエリは現在必要な全データをインデックスから取得しており、基本テーブルにアクセスしていません（`operator info`: `index:IndexRangeScan_11`）。この種のインデックスはカバリングインデックスとして知られています。読み取りパフォーマンスは非常に良くなりますが、TiDBはインデックスも更新しなければならないため、テーブルの更新にはパフォーマンスへの悪影響があるかもしれません。


### 手順 5. インデックスを削除


+ この練習で追加したインデックスを削除し、`planetarySystem` テーブルを元の状態に戻します。
  ```sql
  ALTER TABLE planetarySystem DROP INDEX idx_hostname_disc_year_pl_name;
  ```
  ```output
  Query OK, 0 rows affected (0.35 sec)
  ```


## モジュール 4: JOIN によるインデックス戦略


+ このモジュールでは、次の2つのクエリを最適化します：


  ```sql
  SELECT A.pl_name, A.hostname, A.discoverymethod, A.disc_year,B.name as DiscoveryFacility, C.ref_name as ParameterReference
  FROM planetarySystem A, discoveryFacility B, parameterReference C
  WHERE A.df_id = B.id AND A.ref_id = C.id AND C.ref_name LIKE 'Rosenthal%' AND A.hostname LIKE '14 Her' AND A.disc_year > 2020;
  ```


  ```sql
  SELECT * FROM planetarySystem WHERE ref_id IN ( SELECT ID FROM parameterReference WHERE ref_name LIKE 'Rosenthal%');
  ```


### 手順 1. 次のクエリの実行計画を確認する


  ```sql
  EXPLAIN SELECT A.pl_name, A.hostname, A.discoverymethod, A.disc_year,B.name as DiscoveryFacility, C.ref_name as ParameterReference
  FROM planetarySystem A, discoveryFacility B, parameterReference C
  WHERE A.df_id = B.id AND A.ref_id = C.id AND C.ref_name LIKE 'Rosenthal%' AND A.hostname LIKE '14 Her' AND A.disc_year > 2020;
  ```
  ```output
  +------------------------------------+----------+-----------+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | id                                 | estRows  | task      | access object | operator info                                                                                                                                                                                                            |
  +------------------------------------+----------+-----------+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | Projection_13                      | 1.98     | root      |               | universe.planetarysystem.pl_name, universe.planetarysystem.hostname, universe.planetarysystem.discoverymethod, universe.planetarysystem.disc_year, universe.discoveryfacility.name, universe.parameterreference.ref_name |
  | └─IndexJoin_18                     | 1.98     | root      |               | inner join, inner:TableReader_15, outer key:universe.planetarysystem.df_id, inner key:universe.discoveryfacility.id, equal cond:eq(universe.planetarysystem.df_id, universe.discoveryfacility.id)                        |
  |   ├─IndexJoin_31(Build)            | 1.98     | root      |               | inner join, inner:TableReader_27, outer key:universe.planetarysystem.ref_id, inner key:universe.parameterreference.id, equal cond:eq(universe.planetarysystem.ref_id, universe.parameterreference.id)                    |
  |   │ ├─TableReader_40(Build)        | 1.98     | root      |               | data:Selection_39                                                                                                                                                                                                        |
  |   │ │ └─Selection_39               | 1.98     | cop[tikv] |               | gt(universe.planetarysystem.disc_year, 2020), like(universe.planetarysystem.hostname, "14 Her", 92)                                                                                                                      |
  |   │ │   └─TableFullScan_38         | 34713.00 | cop[tikv] | table:A       | keep order:false                                                                                                                                                                                                         |
  |   │ └─TableReader_27(Probe)        | 0.00     | root      |               | data:Selection_26                                                                                                                                                                                                        |
  |   │   └─Selection_26               | 0.00     | cop[tikv] |               | like(universe.parameterreference.ref_name, "Rosenthal%", 92)                                                                                                                                                             |
  |   │     └─TableRangeScan_25        | 1.98     | cop[tikv] | table:C       | range: decided by [universe.planetarysystem.ref_id], keep order:false                                                                                                                                                    |
  |   └─TableReader_15(Probe)          | 1.98     | root      |               | data:TableRangeScan_14                                                                                                                                                                                                   |
  |     └─TableRangeScan_14            | 1.98     | cop[tikv] | table:B       | range: decided by [universe.planetarysystem.df_id], keep order:false                                                                                                                                                     |
  +------------------------------------+----------+-----------+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  11 rows in set (0.01 sec)
  ```
+ 最初に結合される2つのテーブルはどれですか？使用する結合の種類は何ですか？ 
 + 答え: テーブル `planetarySystem` (A) と `parameterReference` (C) が最初に結合され、結合タイプは `IndexJoin` です。
+ どのテーブルが2番目のテーブル結合にのみ参加しますか？使用する結合の種類は何ですか？ 
 + 答え: テーブル `discoveryFacility` (B)、結合タイプは `IndexJoin` です。
+ 各テーブルクエリのアクセスメソッドは何ですか？ 
 + 答え: テーブル `planetarySystem` (A) は `TableFullScan`、`Selection`、`TableReader`；テーブル `parameterReference` (C) は `TableRangeScan`、`Selection`、`TableReader`；テーブル `discoveryFacility` (B) は `TableRangeScan` と `TableReader`。
+ このアクセス戦略は良いパフォーマンスをもたらしますか？ なぜですか？ 
 + 答え: いいえ。これは、`WHERE`句に`C.ref_name LIKE 'Rosenthal%' AND A.hostname LIKE '14 Her' AND A.disc_year > 2020`のようなフィルター条件があるためです。これらのフィルター処理を高速化するためにTiKVノードにインデックスを作成し、`TableFullScan`や`SELECT`のような他のフィルタリング操作を回避することで、IO圧力を軽減することができます。


### 手順 2. インデックスを追加し、次のクエリの実行計画を確認する


  ```sql
  CREATE INDEX idx_hostname_disc_year ON planetarySystem(hostname, disc_year);
  CREATE INDEX idx_ref_name ON parameterReference(ref_name);
  ANALYZE TABLE planetarySystem;
  ANALYZE TABLE parameterReference;
  ```
  ```output
  Query OK, 0 rows affected, 1 warning (0.63 sec)
  ```


  ```sql
  EXPLAIN SELECT A.pl_name, A.hostname, A.discoverymethod, A.disc_year,B.name as DiscoveryFacility, C.ref_name as ParameterReference
  FROM planetarySystem A, discoveryFacility B, parameterReference C
  WHERE A.df_id = B.id AND A.ref_id = C.id AND C.ref_name LIKE 'Rosenthal%' AND A.hostname LIKE '14 Her' AND A.disc_year > 2020;
  ```
  ```output
  +------------------------------------------+---------+-----------+------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | id                                       | estRows | task      | access object                                              | operator info                                                                                                                                                                                                            |
  +------------------------------------------+---------+-----------+------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | Projection_13                            | 1.98    | root      |                                                            | universe.planetarysystem.pl_name, universe.planetarysystem.hostname, universe.planetarysystem.discoverymethod, universe.planetarysystem.disc_year, universe.discoveryfacility.name, universe.parameterreference.ref_name |
  | └─IndexJoin_18                           | 1.98    | root      |                                                            | inner join, inner:TableReader_15, outer key:universe.planetarysystem.df_id, inner key:universe.discoveryfacility.id, equal cond:eq(universe.planetarysystem.df_id, universe.discoveryfacility.id)                        |
  |   ├─HashJoin_37(Build)                   | 1.98    | root      |                                                            | inner join, equal:[eq(universe.planetarysystem.ref_id, universe.parameterreference.id)]                                                                                                                                  |
  |   │ ├─IndexLookUp_43(Build)              | 1.98    | root      |                                                            |                                                                                                                                                                                                                          |
  |   │ │ ├─IndexRangeScan_41(Build)         | 1.98    | cop[tikv] | table:A, index:idx_hostname_disc_year(hostname, disc_year) | range:("14 Her" 2020,"14 Her" +inf], keep order:false                                                                                                                                                                    |
  |   │ │ └─TableRowIDScan_42(Probe)         | 1.98    | cop[tikv] | table:A                                                    | keep order:false                                                                                                                                                                                                         |
  |   │ └─IndexReader_45(Probe)              | 2.72    | root      |                                                            | index:IndexRangeScan_44                                                                                                                                                                                                  |
  |   │   └─IndexRangeScan_44                | 2.72    | cop[tikv] | table:C, index:idx_ref_name(ref_name)                      | range:["Rosenthal","Rosentham"), keep order:false                                                                                                                                                                        |
  |   └─TableReader_15(Probe)                | 1.98    | root      |                                                            | data:TableRangeScan_14                                                                                                                                                                                                   |
  |     └─TableRangeScan_14                  | 1.98    | cop[tikv] | table:B                                                    | range: decided by [universe.planetarysystem.df_id], keep order:false                                                                                                                                                     |
  +------------------------------------------+---------+-----------+------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  10 rows in set (0.01 sec)
  ```
+ 最初に結合される2つのテーブルはどれですか？使用する結合の種類は何ですか？ 
 + 答え: テーブル `planetarySystem` (A) と `parameterReference` (C) が最初に結合され、結合タイプは `HashJoin` です。
+ どのテーブルが2番目のテーブル結合にのみ参加しますか？使用する結合の種類は何ですか？ 
 + 答え: テーブル `discoveryFacility` (B)、結合タイプは `IndexJoin` です。
+ 各テーブルクエリのアクセスメソッドは何ですか？ 
 + 答え: `IndexRangeScan` と `IndexLookUp` はテーブル `planetarySystem` (A); `IndexRangeScan` と `IndexReader` はテーブル `parameterReference` (C); `TableRangeScan` と `TableReader` はテーブル `discoveryFacility` (B)です。
+ このアクセス戦略は良いパフォーマンスをもたらしますか？ なぜですか？ 
 + 答え: はい。これは `TableFullScan` やその他のフィルタリング操作が、インデックスを使用することによって回避されるためです。


### 手順 3. 索引を追加し、次のクエリの実行計画を確認する


  ```sql
  CREATE INDEX idx_ref_id ON planetarySystem(ref_id);
  CREATE INDEX idx_df_id ON planetarySystem(df_id);
  ANALYZE TABLE planetarySystem;
  ```
  ```output
  Query OK, 0 rows affected, 1 warning (4.00 sec)
  ```


  ```sql
  EXPLAIN SELECT A.pl_name, A.hostname, A.discoverymethod, A.disc_year,B.name as DiscoveryFacility, C.ref_name as ParameterReference
  FROM planetarySystem A, discoveryFacility B, parameterReference C
  WHERE A.df_id = B.id AND A.ref_id = C.id AND C.ref_name LIKE 'Rosenthal%' AND A.hostname LIKE '14 Her' AND A.disc_year > 2020;
  ```
  ```output
  +------------------------------------------+---------+-----------+------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | id                                       | estRows | task      | access object                                              | operator info                                                                                                                                                                                                            |
  +------------------------------------------+---------+-----------+------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | Projection_13                            | 1.98    | root      |                                                            | universe.planetarysystem.pl_name, universe.planetarysystem.hostname, universe.planetarysystem.discoverymethod, universe.planetarysystem.disc_year, universe.discoveryfacility.name, universe.parameterreference.ref_name |
  | └─IndexJoin_19                           | 1.98    | root      |                                                            | inner join, inner:TableReader_16, outer key:universe.planetarysystem.df_id, inner key:universe.discoveryfacility.id, equal cond:eq(universe.planetarysystem.df_id, universe.discoveryfacility.id)                        |
  |   ├─HashJoin_71(Build)                   | 1.98    | root      |                                                            | inner join, equal:[eq(universe.planetarysystem.ref_id, universe.parameterreference.id)]                                                                                                                                  |
  |   │ ├─IndexLookUp_85(Build)              | 1.98    | root      |                                                            |                                                                                                                                                                                                                          |
  |   │ │ ├─IndexRangeScan_83(Build)         | 1.98    | cop[tikv] | table:A, index:idx_hostname_disc_year(hostname, disc_year) | range:("14 Her" 2020,"14 Her" +inf], keep order:false                                                                                                                                                                    |
  |   │ │ └─TableRowIDScan_84(Probe)         | 1.98    | cop[tikv] | table:A                                                    | keep order:false                                                                                                                                                                                                         |
  |   │ └─IndexReader_87(Probe)              | 2.72    | root      |                                                            | index:IndexRangeScan_86                                                                                                                                                                                                  |
  |   │   └─IndexRangeScan_86                | 2.72    | cop[tikv] | table:C, index:idx_ref_name(ref_name)                      | range:["Rosenthal","Rosentham"), keep order:false                                                                                                                                                                        |
  |   └─TableReader_16(Probe)                | 1.98    | root      |                                                            | data:TableRangeScan_15                                                                                                                                                                                                   |
  |     └─TableRangeScan_15                  | 1.98    | cop[tikv] | table:B                                                    | range: decided by [universe.planetarysystem.df_id], keep order:false                                                                                                                                                     |
  +------------------------------------------+---------+-----------+------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  10 rows in set (0.01 sec)
  ```


+ 三つのテーブルの結合順序が変わりましたか？ なぜですか？ 
 + 答え: いいえ。オプティマイザーは、各テーブルに関与するデータ量に基づいてテーブルの結合順序を決定することがよくあります。データ量が最も少ないテーブルが最初に結合されます。クエリのフィルタリング条件に基づいて、結合に参加する各テーブルの行数を決定します。以下の通りです。
 
  ```sql
  SELECT COUNT(*) FROM planetarysystem WHERE hostname LIKE '14 Her' AND disc_year > 2020;
  SELECT COUNT(*) FROM parameterReference WHERE ref_name LIKE 'Rosenthal%';
  SELECT COUNT(*) FROM discoveryFacility;
  ```
  ```output
  +----------+
  | COUNT(*) |
  +----------+
  |        2 |
  +----------+
  1 row in set (0.01 sec)
 
  +----------+
  | COUNT(*) |
  +----------+
  |        2 |
  +----------+
  1 row in set (0.00 sec)


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


+ 結論としては、`planetarySystem` と `parameterReference` テーブルは最も少ない行で結合に参加し、`discoveryFacility` テーブルは最も多い行で結合に参加します。


### 手順 4. インデックスを削除


  ```sql
  ALTER TABLE planetarySystem DROP INDEX idx_ref_id;
  ALTER TABLE planetarySystem DROP INDEX idx_df_id;
  ALTER TABLE planetarySystem DROP INDEX idx_hostname_disc_year;
  ALTER TABLE ParameterReference DROP INDEX idx_ref_name;
  ```
  ```output
  Query OK, 0 rows affected (0.52 sec)
  ```


### 手順 5. 次のクエリの実行計画を確認する


  ```sql
  EXPLAIN SELECT * FROM planetarySystem WHERE ref_id IN ( SELECT ID FROM parameterReference WHERE ref_name LIKE 'Rosenthal%');
  ```
  ```output
  tidb>EXPLAIN SELECT * FROM planetarySystem WHERE ref_id IN ( SELECT ID FROM parameterReference WHERE ref_name LIKE 'Rosenthal%');
  +------------------------------+----------+-----------+--------------------------+-----------------------------------------------------------------------------------------+
  | id                           | estRows  | task      | access object            | operator info                                                                           |
  +------------------------------+----------+-----------+--------------------------+-----------------------------------------------------------------------------------------+
  | HashJoin_26                  | 45.97    | root      |                          | inner join, equal:[eq(universe.parameterreference.id, universe.planetarysystem.ref_id)] |
  | ├─TableReader_31(Build)      | 2.72     | root      |                          | data:Selection_30                                                                       |
  | │ └─Selection_30             | 2.72     | cop[tikv] |                          | like(universe.parameterreference.ref_name, "Rosenthal%", 92)                            |
  | │   └─TableFullScan_29       | 2055.00  | cop[tikv] | table:parameterReference | keep order:false                                                                        |
  | └─TableReader_28(Probe)      | 34713.00 | root      |                          | data:TableFullScan_27                                                                   |
  |   └─TableFullScan_27         | 34713.00 | cop[tikv] | table:planetarySystem    | keep order:false                                                                        |
  +------------------------------+----------+-----------+--------------------------+-----------------------------------------------------------------------------------------+
  6 rows in set (0.00 sec)
  ```
+ 結合における結合タイプは何ですか？ 
 + 答え: `HashJoin`
+ 結合におけるテーブルの選択タイプは何ですか？ 
 + 答え: `TableFullScan`, `Selection`, `TableReader` が `parameterReference` テーブルに; `TableFullScan`, `TableReader` が `planetarySystem` テーブルに使用されます。
+ このアクセス戦略は良いパフォーマンスをもたらしますか？ なぜですか？ 
 + 答え: いいえ。まず、WHERE 句でフィルタリングするために、`parameterReference` テーブルのインデックスを作成できます。次に、`planetarySystem` テーブルの結合カラムに対してもインデックスを作成することができます。


### 手順 6. インデックスを追加し、次のクエリの実行計画を確認する


  ```sql
  CREATE INDEX idx_ref_id ON planetarySystem(ref_id);
  CREATE INDEX idx_ref_name ON ParameterReference(ref_name);
  ANALYZE TABLE planetarySystem;
  ANALYZE TABLE ParameterReference;
  ```
  ```output
  Query OK, 0 rows affected, 1 warning (0.83 sec)
  ```


  ```sql
  EXPLAIN SELECT * FROM planetarySystem WHERE ref_id IN ( SELECT ID FROM parameterReference WHERE ref_name LIKE 'Rosenthal%');
  ```
  ```output
  +----------------------------------+---------+-----------+--------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | id                               | estRows | task      | access object                                          | operator info                                                                                                                                                                                         |
  +----------------------------------+---------+-----------+--------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | IndexHashJoin_20                 | 45.97   | root      |                                                        | inner join, inner:IndexLookUp_17, outer key:universe.parameterreference.id, inner key:universe.planetarysystem.ref_id, equal cond:eq(universe.parameterreference.id, universe.planetarysystem.ref_id) |
  | ├─IndexReader_46(Build)          | 2.72    | root      |                                                        | index:IndexRangeScan_45                                                                                                                                                                               |
  | │ └─IndexRangeScan_45            | 2.72    | cop[tikv] | table:parameterReference, index:idx_ref_name(ref_name) | range:["Rosenthal","Rosentham"), keep order:false                                                                                                                                                     |
  | └─IndexLookUp_17(Probe)          | 45.97   | root      |                                                        |                                                                                                                                                                                                       |
  |   ├─IndexRangeScan_15(Build)     | 45.97   | cop[tikv] | table:planetarySystem, index:idx_ref_id(ref_id)        | range: decided by [eq(universe.planetarysystem.ref_id, universe.parameterreference.id)], keep order:false                                                                                             |
  |   └─TableRowIDScan_16(Probe)     | 45.97   | cop[tikv] | table:planetarySystem                                  | keep order:false                                                                                                                                                                                      |
  +----------------------------------+---------+-----------+--------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  6 rows in set (0.00 sec)
  ```


+ 結合における結合タイプは何ですか？ 
 + 答え: `IndexHashJoin`
+ 結合におけるテーブルの選択タイプは何ですか？ 
 + 答え: `IndexRangeScan` と `IndexReader` は `parameterReference` テーブルに; `IndexRangeScan` と `IndexLookUp` は `planetarySystem` テーブルに使用されます。
+ このアクセス戦略は良いパフォーマンスをもたらしますか？ なぜですか？ 
 + 答え: はい。`idx_ref_id` のインデックスによって `planetarySystem` テーブルの結合カラムにインデックスが存在することが保証され、`HashJoin` は `IndexHashJoin` に変わり、これにより完全なテーブルスキャンを避けることができます。同時に `ParameterReference` テーブルに `idx_ref_name` インデックスが存在することを保証することにより、フィルタリングが最初に行われ、完全なテーブルスキャンを避けることができます。


### 手順 7. インデックスを削除


  ```sql
  DROP INDEX idx_ref_id ON planetarysystem;
  DROP INDEX idx_ref_name ON parameterreference;
  ```
  ```output
  Query OK, 0 rows affected (0.52 sec)
  ```


## 演習終了

