TiDBへのデータのImport 〜 IMPORT INTO

## はじめに

TiDBへのデータのImportはいくつかありますが、大きく分けて物理モードと論理モードの2つの手段があります。

- 物理モード: TiKVに直接データを投入する。高速
- 論理モード: INSERT文でデータを投入する。普通

この物理モードを利用できる手段は長らく [TiDB Lightning]() のみでしたが、最近内部的にLightningを利用する `IMPORT INTO` 文が実装されました。

本記事ではこの `IMPORT INTO` 文を利用した方法について説明します。ローカルファイルをTiUPで起動したTiDB Playgroundで読み込んでみるのと、s3に出力したファイルをTiDB Cloud Dedicatedで読み込んでみるパターンの２つを試してみます。

:::note warn
`IMPORT INTO` は現在のところTiDB Cloud Dedicated, OSS版のTiDBで利用可能です。TiDB Cloud ServerlessではWebからImportメニューを利用してください。
:::

## ローカルファイルをTiDB OSSで読み込む

### データの準備

https://qiita.com/bohnen/items/c65f382d2b7f64ad3ef0#mysql%E3%81%8B%E3%82%89%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88-tidb%E7%A7%BB%E8%A1%8C%E7%94%A8

こちらの記事で実施した、Dumplingでローカルファイルに出力したsql形式の出力を利用します。

```bash
tiup dumpling -h 127.0.0.1 -P 3306 -u root -p <password> \
-B employees -o output/ --filetype sql

```

### TiDBの起動とIMPORT INTOの実施

まずはTiUPでPlaygroundを起動します。バージョンは v8.1.1 を指定しました。

```bash
> tiup playground v8.1.1

🎉 TiDB Playground Cluster is started, enjoy!

Connect TiDB:    mysql --host 127.0.0.1 --port 4000 -u root
TiDB Dashboard:  http://127.0.0.1:2379/dashboard
Grafana:         http://127.0.0.1:3000
```

接続できたら、出力された通りにMySQLクライアントから接続します。
IMPORT INTO では事前にテーブルを作成して置く必要があります。ここではemployeesテーブルを事前に作成しておきましょう。

```sql
mysql> source output/employees-schema-create.sql -- databaseの作成
mysql> use employees; 
mysql> source source output/employees.employees-schema.sql -- employeesテーブルの作成
```

ではIMPORT INTOを実施します。ファイルを直接読み込む場合、パスはTiDBと同じサーバでフルパスで指定する必要があります。ファイル名にはワイルドカードが利用できます。

```sql
mysql> IMPORT INTO employees FROM '/Users/.../output/employees.employees.*.sql' FORMAT 'sql';
+--------+--------------------------------------------------------------------------+-------------------------+----------+-------+----------+------------------+---------------+----------------+----------------------------+----------------------------+----------------------------+------------+
| Job_ID | Data_Source                                                              | Target_Table            | Table_ID | Phase | Status   | Source_File_Size | Imported_Rows | Result_Message | Create_Time                | Start_Time                 | End_Time                   | Created_By |
+--------+--------------------------------------------------------------------------+-------------------------+----------+-------+----------+------------------+---------------+----------------+----------------------------+----------------------------+----------------------------+------------+
|      1 | /Users/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/output/employees.employees.*.sql | `employees`.`employees` |      106 |       | finished | 16.9MiB          |        300024 |                | 2024-12-16 16:58:23.122401 | 2024-12-16 16:58:23.640002 | 2024-12-16 16:58:29.153543 | root@%     |
+--------+--------------------------------------------------------------------------+-------------------------+----------+-------+----------+------------------+---------------+----------------+----------------------------+----------------------------+----------------------------+------------+
1 row in set (0.01 sec)
1 row in set (6.34 sec)

```

このようにジョブの形で非同期で実行されますが、この例の場合はデータ量が少なかったのでもう終わっています。ジョブの実行状況は `SHOW IMPORT JOBS` でも確認できます。

データが入っていることを確認してみます。

```sql
select * from employees limit 5;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  |
+--------+------------+------------+-----------+--------+------------+
|  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
|  10002 | 1964-06-02 | Bezalel    | Simmel    | F      | 1985-11-21 |
|  10003 | 1959-12-03 | Parto      | Bamford   | M      | 1986-08-28 |
|  10004 | 1954-05-01 | Chirstian  | Koblick   | M      | 1986-12-01 |
|  10005 | 1955-01-21 | Kyoichi    | Maliniak  | M      | 1989-09-12 |
+--------+------------+------------+-----------+--------+------------+
5 rows in set (0.00 sec)
```

問題なさそうです。

## TiDB CloudにS3からIMPORTしてみる。

今度はTiDB Cloudからcsvファイルを読み込んでみます。

### 準備

https://qiita.com/bohnen/items/c65f382d2b7f64ad3ef0#mysqltidb%E3%81%8B%E3%82%89s3%E3%81%AB%E5%88%86%E6%9E%90%E7%94%A8%E3%81%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88

こちらの例を使って、DumplingでS3に出力します。

```bash
tiup dumpling -h 127.0.0.1 -P 3306 -u root -p <password> \
-B employees -o s3://<bucket>/ --filetype csv --compress gz \
-m --output-filename-template '{{.DB}}/{{.Table}}/{{.Index}}'

```

### TiDB Cloudへの接続とIMPORT INTO

TiDB Cloudへ接続して、OSS版同様にdatabaseとtableを作成しておきます。
（ここの手順は割愛します）

その後、IMPORT INTO を実行します。

```sql

IMPORT INTO employees FROM 's3://.../employees/employees/*.csv.gz?access-key=<accesskey>&secret-access-key=<secret>&session-token=<token>' WITH skip_rows=1;

```

OSS版同様、s3のパスを記述します。s3へのアクセスするために必要なクレデンシャルは、クエリパラメーター形式で指定します。今回は、IAMのアクセスキーを指定しています。

:::note warn
アクセスキーをSSOから取得した場合は、`session-token` も指定する必要があるので注意してください。
:::

## おわりに

`IMPORT INTO` はTiDB Cloud Dedicated、およびOSS版で利用可能な、高速なインポート方法です。TiDB Cloud Serverlessでは残念ながら利用できませんが、同じデータソースから利用可能なGUIのimportがありますので、そちらを利用すると良いです。