挿入
説明
change文は、データ挿入操作を完了するためのものです。
INSERT INTO table_name
[ PARTITION (p1, ...) ]
[ WITH LABEL label]
[ (column [, ...]) ]
[ [ hint [, ...] ] ]
{ VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
パラメータ
tablet_name: データをインポートする宛先テーブル。
db_name.table_nameの形式で指定可能partitions: インポートするパーティションを指定。
table_nameに存在するパーティションである必要があります。複数のパーティション名はカンマで区切りますlabel: Insertタスクのラベルを指定
column_name: 指定する宛先カラム。
table_nameに存在するカラムである必要がありますexpression: カラムに割り当てる必要がある対応する式
DEFAULT: 対応するカラムにデフォルト値を使用させる
query: 一般的なクエリ。クエリの結果がターゲットに書き込まれます
hint:
INSERTの実行動作を示すために使用されるインジケータ。次の値のいずれかを選択できます:/*+ STREAMING */、/*+ SHUFFLE */、または/*+ NOSHUFFLE */。
- STREAMING: 現在、実質的な効果はなく、以前のバージョンとの互換性のためのみに保持されています。(以前のバージョンでは、このhintを追加するとlabelが返されましたが、現在はデフォルトでlabelを返します)
- SHUFFLE: ターゲットテーブルがパーティションテーブルの場合、このhintを有効にするとrepartiitonが実行されます。
- NOSHUFFLE: ターゲットテーブルがパーティションテーブルであってもrepartiitonは実行されませんが、データが各パーティションに正しく配置されることを保証するために他のいくつかの操作が実行されます。
merge-on-writeが有効なUniqueテーブルの場合、insert文を使用して部分的なカラム更新も実行できます。insert文で部分的なカラム更新を実行するには、セッション変数enable_unique_key_partial_updateをtrue に設定する必要があります(この変数のデフォルト値はfalseで、デフォルトではinsert文での部分的なカラム更新は許可されません)。部分的なカラム更新を実行する際、挿入するカラムは少なくともすべてのKeyカラムを含み、更新したいカラムを指定する必要があります。挿入する行のKeyカラム値が元のテーブルに既に存在する場合、同じキーカラム値を持つ行のデータが更新されます。挿入する行のKeyカラム値が元のテーブルに存在しない場合、新しい行がテーブルに挿入されます。この場合、insert文で指定されていないカラムは、デフォルト値を持つかnull許可である必要があります。これらの欠落したカラムは、最初にデフォルト値で埋められることが試行され、カラムにデフォルト値がない場合はnullで埋められます。カラムがnullにできない場合、insert操作は失敗します。
insert文が厳密モードで動作するかどうかを制御するセッション変数enable_insert_strictのデフォルト値はtrueであることにご注意ください。つまり、insert文はデフォルトで厳密モードになっており、このモードでは部分的なカラム更新において存在しないキーの更新は許可されません。したがって、insert文を部分的なカラム更新に使用し、存在しないキーを挿入したい場合は、enable_unique_key_partial_updateをtrueに設定し、同時にenable_insert_strictをfalseに設定する必要があります。
注意:
INSERT文を実行する際のデフォルトの動作は、文字列が長すぎるなど、ターゲットテーブルの形式に適合しないデータをフィルタリングすることです。ただし、データがフィルタリングされないことを要求するビジネスシナリオの場合、セッション変数enable_insert_strictをtrueに設定して、データがフィルタリングされる際にINSERTが正常に実行されないことを保証できます。
例
testテーブルには2つのカラムc1、c2が含まれています。
testテーブルに1行のデータをインポート
INSERT INTO test VALUES (1, 2);
INSERT INTO test (c1, c2) VALUES (1, 2);
INSERT INTO test (c1, c2) VALUES (1, DEFAULT);
INSERT INTO test (c1) VALUES (1);
1番目と2番目のステートメントは同じ効果を持ちます。ターゲットカラムが指定されていない場合、テーブル内のカラムの順序がデフォルトのターゲットカラムとして使用されます。
3番目と4番目のステートメントは同じ意味を表し、c2カラムのデフォルト値を使用してデータインポートを完了します。
- 複数行のデータを
testテーブルに一度にインポートする
INSERT INTO test VALUES (1, 2), (3, 2 + 2);
INSERT INTO test (c1, c2) VALUES (1, 2), (3, 2 * 2);
INSERT INTO test (c1) VALUES (1), (3);
INSERT INTO test (c1, c2) VALUES (1, DEFAULT), (3, DEFAULT);
最初と2番目のステートメントは同じ効果があり、testテーブルに2つのデータを一度にインポートします
3番目と4番目のステートメントの効果は既知であり、c2列のデフォルト値を使用してtestテーブルに2つのデータをインポートします
- クエリ結果を
testテーブルにインポートする
INSERT INTO test SELECT * FROM test2;
INSERT INTO test (c1, c2) SELECT * from test2;
- クエリ結果を
testテーブルにインポートし、パーティションとラベルを指定する
INSERT INTO test PARTITION(p1, p2) WITH LABEL `label1` SELECT * FROM test2;
INSERT INTO test WITH LABEL `label1` (c1, c2) SELECT * from test2;
Keywords
INSERT
ベストプラクティス
-
返された結果を確認する
INSERT操作は同期操作であり、結果の返却は操作の終了を示します。ユーザーは異なる返却結果に応じて対応する処理を実行する必要があります。
-
実行が成功し、結果セットが空の場合
select文に対応するinsertの結果セットが空の場合、以下のように返却されます:
mysql> insert into tbl1 select * from empty_tbl;
Query OK, 0 rows affected (0.02 sec)
-
Query OKは実行が成功したことを示します。0 rows affectedは、データがインポートされなかったことを意味します。
-
実行が成功し、結果セットが空ではない
結果セットが空ではない場合。返される結果は以下の状況に分けられます:
-
Insertが正常に実行され、可視である:
mysql> insert into tbl1 select * from tbl2;
Query OK, 4 rows affected (0.38 sec)
{'label':'insert_8510c568-9eda-4173-9e36-6adc7d35291c', 'status':'visible', 'txnId':'4005'}
mysql> insert into tbl1 with label my_label1 select * from tbl2;
Query OK, 4 rows affected (0.38 sec)
{'label':'my_label1', 'status':'visible', 'txnId':'4005'}
mysql> insert into tbl1 select * from tbl2;
Query OK, 2 rows affected, 2 warnings (0.31 sec)
{'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4020d', 'status':'visible', 'txnId':'4005'}
mysql> insert into tbl1 select * from tbl2;
Query OK, 2 rows affected, 2 warnings (0.31 sec)
{'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4020d', 'status':'committed', 'txnId':'4005'}
-
Query OKは実行が成功したことを示します。4 rows affectedは合計4行のデータがインポートされたことを意味します。2 warningsはフィルタリングされる行数を示します。
また、json文字列を返します:
```json
{'label':'my_label1', 'status':'visible', 'txnId':'4005'}
{'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4020d', 'status':'committed', 'txnId':'4005'}
{'label':'my_label1', 'status':'visible', 'txnId':'4005', 'err':'some other error'}
```
labelはユーザー指定のラベルまたは自動生成されたラベルです。LabelはこのInsert IntoインポートジョブのIDです。各インポートジョブは単一のデータベース内で一意のLabelを持ちます。
`status`はインポートされたデータが表示可能かどうかを示します。表示可能な場合は`visible`、表示不可能な場合は`committed`を表示します。
`txnId`はこのinsertに対応するインポートトランザクションのidです。
`err`フィールドはその他の予期しないエラーを表示します。
フィルタリングされた行を表示する必要がある場合、ユーザーは以下のステートメントを渡すことができます
```sql
show load where label="xxx";
```
返されたURLは不正なデータのクエリに使用できます。詳細については、後述のエラー行の表示の要約を参照してください。
**データの不可視状態は一時的な状態であり、このバッチのデータは最終的に可視化されます**
このバッチのデータの可視状態は、以下のステートメントで確認できます:
```sql
show transaction where id=4005;
```
返された結果のTransactionStatus列がvisibleの場合、表現データは可視状態です。
-
実行失敗
実行失敗は、データが正常にインポートされなかったことを示し、以下が返されます:
mysql> insert into tbl1 select * from tbl2 where k1 = "a";
ERROR 1064 (HY000): all partitions have no load data. url: http://10.74.167.16:8042/api/_load_error_log?file=__shard_2/error_log_insert_stmt_ba8bb9e158e4879-ae8de8507c0bf8a2_ba8bb9e158e4879_ae8de8507c0
ERROR 1064 (HY000): all partitions have no load dataが失敗の原因を示しています。以下のurlを使用して間違ったデータを照会できます:
```sql
show load warnings on "url";
```
特定のエラー行を確認できます。
-
タイムアウト時間
INSERT操作のタイムアウトは、max(insert_timeout, query_timeout)によって制御されます。両方とも環境変数で、insert_timeoutのデフォルトは4時間、query_timeoutのデフォルトは5分です。操作がタイムアウトを超えた場合、ジョブはキャンセルされます。insert_timeoutの導入は、INSERT文がより長いデフォルトタイムアウトを持つことを保証し、インポートタスクが通常のクエリに適用される短いデフォルトタイムアウトの影響を受けないようにするためです。
-
ラベルと原子性
INSERT操作は、インポートの原子性も保証します。Import Transactions and Atomicityドキュメントを参照してください。
insert操作でクエリ部分として
CTE(Common Table Expressions)を使用する場合、WITH LABELとcolumn部分を指定する必要があります。 -
フィルタ閾値
他のインポート方法とは異なり、INSERT操作ではフィルタ閾値(
max_filter_ratio)を指定できません。デフォルトのフィルタ閾値は1で、これはエラーのある行を無視できることを意味します。データをフィルタリングしないことが要求されるビジネスシナリオでは、session variable
enable_insert_strictをtrueに設定することで、データがフィルタリングされる場合にINSERTが正常に実行されないことを保証できます。 -
パフォーマンスの問題
VALUES方式を使用した単一行挿入はありません。この方法を使用する必要がある場合は、複数行のデータを1つのINSERT文にまとめて一括コミットしてください。