MaxCompute では、INSERT INTO または INSERT OVERWRITE を使用して、ターゲットテーブルまたは静的パーティションにデータを挿入または上書きできます。
このトピックのコマンドは、次のプラットフォームで実行できます:
前提条件
INSERT INTO および INSERT OVERWRITE 操作を実行するには、ターゲットテーブルに対する Update 権限と、ソーステーブルに対する Select 権限が必要です。権限の付与に関する詳細については、「MaxCompute 権限」をご参照ください。
概要
MaxCompute SQL でデータを処理する場合、INSERT INTO または INSERT OVERWRITE 文を使用して、SELECT クエリの結果をターゲットテーブルに保存できます。違いは次のとおりです:
INSERT INTO:テーブルまたは静的パーティションにデータを追記します。INSERT文でパーティション値を指定して、特定のパーティションにデータを挿入できます。少量のテストデータを挿入するには、この文を VALUES とともに使用します。INSERT OVERWRITE:テーブルまたは静的パーティションの既存のデータをクリアしてから、新しいデータを挿入します。説明MaxCompute の
INSERT構文は、MySQL や Oracle のINSERT構文とは異なります。INSERT INTOとINSERT OVERWRITEの両方の文でTABLEキーワードを省略できます。同じパーティションに対して
INSERT OVERWRITE操作を繰り返し実行すると、DESCコマンドによって返されるパーティションのSizeが異なる場合があります。これは、パーティションからデータをSELECTし、そのデータをINSERT OVERWRITEを使用して同じパーティションに書き戻す際に、ファイル分割ロジックが変更されるためです。その結果、データのSizeも変化します。INSERT OVERWRITE操作の前後で合計データ長は同じままであり、追加のストレージ料金は発生しません。
動的パーティションへのデータ挿入方法については、「動的パーティションへのデータの挿入または上書き (DYNAMIC PARTITION)」をご参照ください。
制限事項
INSERT INTOおよびINSERT OVERWRITEを使用してテーブルまたは静的パーティションのデータを更新する場合、次の制限事項があります:INSERT INTO:クラスター化テーブルにデータを追記することはできません。INSERT OVERWRITE:挿入する列の指定はサポートされていません。列を指定するには、INSERT INTOを使用します。たとえば、CREATE TABLE t(a STRING, b STRING); INSERT INTO t(a) VALUES ('1');という文は、列 a に '1' を挿入し、列 b を NULL またはそのデフォルト値に設定します。MaxCompute はテーブルロックを実装していません。同じテーブルに対して
INSERT INTOまたはINSERT OVERWRITE操作を同時に実行しないでください。
Delta テーブルには、次の制限事項があります。
INSERT OVERWRITEを使用して Delta テーブルにデータを書き込む際、同じ PK 値を持つ複数の行は、書き込み前に重複排除されます。最初の行のみが書き込まれます。最終的な結果は、計算プロセス中のレコードの順序に依存し、手動で指定することはできません。この操作はデータセット全体を書き込むため、このデフォルトの重複排除はプライマリキーの一意性を保証するのに役立ちます。INSERT INTOを使用して Delta テーブルにデータを書き込む場合、デフォルトでは、同じ主キー (PK) 値を持つ複数の行は重複排除されず、すべてがテーブルに書き込まれます。ただし、set odps.sql.insert.acidtable.deduplicate.enable = trueを設定した場合、データはテーブルに書き込まれる前に重複排除されます。
構文
INSERT {INTO|OVERWRITE} TABLE <table_name> [PARTITION (<pt_spec>)] [(<col_name> [,<col_name> ...)]]
<select_statement>
FROM <from_statement>
[ZORDER BY <zcol_name> [, <zcol_name> ...]];次の表で各パラメーターについて説明します。
パラメーター | 必須 | 説明 |
table_name | はい | データを挿入するターゲットテーブルの名前。 |
pt_spec | いいえ | データを挿入するパーティション。定数を指定する必要があります。関数や式は使用できません。 形式は |
col_name | いいえ | データを挿入するターゲットテーブルの列名。
|
select_statement | はい | ソーステーブルから挿入するデータをクエリする 説明
|
from_statement | はい | ソーステーブル名などのデータソースを指定する |
ZORDER BY <zcol_name> [, <zcol_name> ...] | いいえ | テーブルまたはパーティションにデータを書き込む際に、1 つ以上の指定された列 (select_statement に対応するテーブル内の列) でデータをソートすることで、類似したデータを持つ行をグループ化できます。これにより、クエリのフィルタリングパフォーマンスが向上し、ストレージコストを削減できます。 |
ZORDER BY と SORT BY の違いは次のとおりです:
ZORDER BYには、ローカル zorder とグローバル zorder の 2 つのモードがあります。デフォルトモードはlocal zorderです。ローカルモードは、個々のファイル内でのみデータを Z オーダーでソートし、データをグローバルに再配布しません。そのため、データが複数のファイルに分散している場合、データのクラスタリングが低くなり、効果的なデータスキップが妨げられる可能性があります。この問題に対処するため、新しいバージョンではglobal zorderがサポートされています。global zorderモードを使用するには、次のパラメーターを設定します:SET odps.sql.default.zorder.type=global;。ZORDER BYには、次の 制限事項 があります:パーティションテーブルの場合、一度に 1 つのパーティションに対してのみ
ZORDER BYソートを実行できます。ZORDER BYの列数は 2 から 4 の間でなければなりません。ターゲットテーブルがクラスター化テーブルの場合、
ZORDER BY句はサポートされていません。ZORDER BYはDISTRIBUTE BYと併用できますがORDER BY、CLUSTER BY、またはSORT BYとは併用できません。
説明ZORDER BY句を使用してデータを書き込む場合、操作はソートしない場合よりも多くのリソースを消費し、時間がかかります。SORT BY文は、単一ファイル内でデータがどのようにソートされるかを指定するために使用されます。SORT BYを指定しない場合、単一ファイル内のデータはlocal zorderでソートされます。
例:通常のテーブル
例 1:
INSERT INTOコマンドを実行して、非パーティション化テーブルwebsitesにデータを追記します。コマンドは次のとおりです:-- websites という名前の非パーティション化テーブルを作成します。 CREATE TABLE IF NOT EXISTS websites (id INT, name STRING, url STRING ); -- apps という名前の非パーティション化テーブルを作成します。 CREATE TABLE IF NOT EXISTS apps (id INT, app_name STRING, url STRING ); -- apps テーブルにデータを追記します。`INSERT INTO TABLE ` の TABLE キーワードは省略可能です。 INSERT INTO apps (id,app_name,url) VALUES (1,'Aliyun','https://www.aliyun.com'); -- apps テーブルからデータをコピーし、websites テーブルに追記します。 INSERT INTO websites (id,name,url) SELECT id,app_name,url FROM apps; -- SELECT 文を実行して websites テーブルのデータを表示します。 SELECT * FROM websites;次の結果が返されます:
-- 結果 +------------+------------+------------+ | id | name | url | +------------+------------+------------+ | 1 | Aliyun | https://www.aliyun.com | +------------+------------+------------+例 2:
INSERT INTOコマンドを実行して、パーティションテーブルsale_detailにデータを追記します。コマンドの例を次に示します:-- sale_detail という名前のパーティションテーブルを作成します。 CREATE TABLE IF NOT EXISTS sale_detail ( shop_name STRING, customer_id STRING, total_price DOUBLE ) PARTITIONED BY (sale_date STRING, region STRING); -- ソーステーブルにパーティションを追加します。この手順は任意です。パーティションが存在しない場合は、データ書き込み時に自動的に作成されます。 ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china'); -- ソーステーブルにデータを追記します。INSERT INTO および INSERT OVERWRITE の後の TABLE キーワードは省略可能です。 INSERT INTO sale_detail PARTITION (sale_date='2013', region='china') VALUES ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3); -- 現在のセッションでのみフルテーブルスキャンを有効にします。SELECT 文を実行して sale_detail テーブルのデータを表示します。 SET odps.sql.allow.fullscan=true; SELECT * FROM sale_detail;次の結果が返されます:
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | +------------+-------------+-------------+------------+------------+例 3:
INSERT OVERWRITEコマンドを実行して、sale_detail_insertテーブルのデータを上書きします。コマンドの例を次に示します:-- sale_detail と同じスキーマを持つターゲットテーブル sale_detail_insert を作成します。 CREATE TABLE sale_detail_insert LIKE sale_detail; -- ターゲットテーブルにパーティションを追加します。この手順は任意です。パーティションが存在しない場合は、データ書き込み時に自動的に作成されます。 ALTER TABLE sale_detail_insert ADD PARTITION (sale_date='2013', region='china'); -- 静的パーティションを上書きします。静的パーティションの場合、パーティション列は PARTITION() 句で指定され、SELECT リストに含めることはできません。SELECT リストの列は、位置に基づいてターゲットテーブルの列にマッピングされます。 SET odps.sql.allow.fullscan=true; INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date='2013', region='china') SELECT shop_name, customer_id, total_price FROM sale_detail ZORDER BY customer_id, total_price; -- 現在のセッションでのみフルテーブルスキャンを有効にします。SELECT 文を実行して sale_detail_insert テーブルのデータを表示します。 SET odps.sql.allow.fullscan=true; SELECT * FROM sale_detail_insert;次の結果が返されます:
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | +------------+-------------+-------------+------------+------------+例 4:
INSERT OVERWRITEコマンドを実行して、sale_detail_insertテーブルのデータを上書きし、SELECT句の列の順序を変更します。ソーステーブルとターゲットテーブルのマッピングは、列名ではなくSELECT句の列の順序に基づいています。コマンドは次のとおりです:SET odps.sql.allow.fullscan=true; INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date='2013', region='china') SELECT customer_id, shop_name, total_price FROM sale_detail; SET odps.sql.allow.fullscan=true; SELECT * FROM sale_detail_insert;次の結果が返されます:
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | c1 | s1 | 100.1 | 2013 | china | | c2 | s2 | 100.2 | 2013 | china | | c3 | s3 | 100.3 | 2013 | china | +------------+-------------+-------------+------------+------------+sale_detail_insertテーブルが作成されたときの列の順序は次のとおりでした:+-------------------+--------------------+-------------------+ | shop_name STRING | customer_id STRING| total_price DOUBLE| +-------------------+--------------------+-------------------+sale_detailからsale_detail_insertへのデータ挿入の順序は次のとおりです:+---------------------+--------------------+-------------------+ | customer_id STRING | shop_name STRING | total_price DOUBLE| +---------------------+--------------------+-------------------+この場合、
sale_detail.customer_idのデータはsale_detail_insert.shop_nameに挿入され、sale_detail.shop_nameのデータはsale_detail_insert.customer_idに挿入されます。例 5:パーティションにデータを挿入する場合、パーティション列は
SELECT句に含めることはできません。次の文はエラーを返します。なぜなら、sale_dateとregionはパーティション列であり、静的パーティションのSELECT句では許可されていないためです。不正なコマンドの例を次に示します:INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date='2013', region='china') SELECT shop_name, customer_id, total_price, sale_date, region FROM sale_detail;例 6:
PARTITIONの値は定数のみ可能で、式は使用できません。不正なコマンドの例を次に示します:INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date=datepart('2016-09-18 01:10:00', 'yyyy') , region='china') SELECT shop_name, customer_id, total_price FROM sale_detail;例 7:
INSERT OVERWRITEコマンドを実行してmf_srcとmf_zorder_srcテーブルのデータを上書きし、mf_zorder_srcテーブルをグローバル Z オーダーモードでソートします。コマンドの例を次に示します:-- ターゲットテーブル mf_src を作成します。 CREATE TABLE mf_src (key STRING, value STRING); INSERT OVERWRITE TABLE mf_src SELECT a, b FROM VALUES ('1', '1'),('3', '3'),('2', '2') AS t(a, b); SELECT * FROM mf_src; -- 次の結果が返されます。 +-----+-------+ | key | value | +-----+-------+ | 1 | 1 | | 3 | 3 | | 2 | 2 | +-----+-------+ -- mf_src と同じスキーマを持つターゲットテーブル mf_zorder_src を作成します。 CREATE TABLE mf_zorder_src LIKE mf_src; -- ソートにグローバル Z オーダーモードを使用します。 SET odps.sql.default.zorder.type=global; INSERT OVERWRITE TABLE mf_zorder_src SELECT key, value FROM mf_src ZORDER BY key, value; SELECT * FROM mf_zorder_src;次の結果が返されます:
+-----+-------+ | key | value | +-----+-------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +-----+-------+例 8:
INSERT OVERWRITEコマンドを実行して、既存のtargetテーブルのデータを上書きします。コマンドは次のとおりです:-- 'target' テーブルは既存のテーブルです。 SET odps.sql.default.zorder.type=global; INSERT OVERWRITE TABLE target SELECT key, value FROM target ZORDER BY key, value;
例:Delta テーブル
例:Delta テーブル mf_dt を作成し、INSERT コマンドを実行してデータを挿入および上書きします。
-- mf_dt という名前の Delta テーブルを作成します。
CREATE TABLE IF NOT EXISTS mf_dt (pk BIGINT NOT NULL PRIMARY KEY,
val BIGINT NOT NULL)
PARTITIONED BY (dd STRING, hh STRING)
tblproperties ("transactional"="true");
-- mf_dt テーブルの dd='01' かつ hh='01' のパーティションにテストデータを挿入します。
INSERT OVERWRITE TABLE mf_dt PARTITION (dd='01', hh='01')
VALUES (1, 1), (2, 2), (3, 3);
-- mf_dt テーブルのターゲットパーティションのデータをクエリします。
SELECT * FROM mf_dt WHERE dd='01' AND hh='01';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk | val | dd | hh |
+------------+------------+----+----+
| 1 | 1 | 01 | 01 |
| 3 | 3 | 01 | 01 |
| 2 | 2 | 01 | 01 |
+------------+------------+----+----+
-- 'INSERT INTO' を使用して mf_dt テーブルのターゲットパーティションにデータを追記します。
INSERT INTO TABLE mf_dt PARTITION(dd='01', hh='01')
VALUES (3, 30), (4, 4), (5, 5);
SELECT * FROM mf_dt WHERE dd='01' AND hh='01';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk | val | dd | hh |
+------------+------------+----+----+
| 1 | 1 | 01 | 01 |
| 3 | 30 | 01 | 01 |
| 4 | 4 | 01 | 01 |
| 5 | 5 | 01 | 01 |
| 2 | 2 | 01 | 01 |
+------------+------------+----+----+
-- 'INSERT OVERWRITE' を使用して mf_dt テーブルのターゲットパーティションのデータを上書きします。
INSERT OVERWRITE TABLE mf_dt PARTITION (dd='01', hh='01')
VALUES (1, 1), (2, 2), (3, 3);
SELECT * FROM mf_dt WHERE dd='01' AND hh='01';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk | val | dd | hh |
+------------+------------+----+----+
| 1 | 1 | 01 | 01 |
| 3 | 3 | 01 | 01 |
| 2 | 2 | 01 | 01 |
+------------+------------+----+----+
-- 'INSERT OVERWRITE' を使用して mf_dt テーブルの dd='01' かつ hh='02' のパーティションにデータを書き込みます。
INSERT OVERWRITE TABLE mf_dt PARTITION (dd='01', hh='02')
VALUES (1, 11), (2, 22), (3, 32);
SELECT * FROM mf_dt WHERE dd='01' AND hh='02';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk | val | dd | hh |
+------------+------------+----+----+
| 1 | 11 | 01 | 02 |
| 3 | 32 | 01 | 02 |
| 2 | 22 | 01 | 02 |
+------------+------------+----+----+
-- 現在のセッションでのみフルテーブルスキャンを有効にします。SELECT 文を実行して mf_dt テーブルのデータを表示します。
SET odps.sql.allow.fullscan=true;
SELECT * FROM mf_dt;
-- 次の結果が返されます。
+------------+------------+----+----+
| pk | val | dd | hh |
+------------+------------+----+----+
| 1 | 11 | 01 | 02 |
| 3 | 32 | 01 | 02 |
| 2 | 22 | 01 | 02 |
| 1 | 1 | 01 | 01 |
| 3 | 3 | 01 | 01 |
| 2 | 2 | 01 | 01 |
+------------+------------+----+----+ベストプラクティス
Z オーダーはすべてのシナリオに適しているわけではありません。ユースケースで実験して、ストレージとクエリパフォーマンスの利点が、Z オーダーデータを書き込むための追加の計算コストを正当化するかどうかを判断する必要がある場合があります。以下のセクションでは、一般的な推奨事項を説明します。
Zオーダーよりもクラスター化インデックスを選択する場合
フィルター条件が通常、列のプレフィックス (例:
a、a and b、またはa and b and c) に基づいている場合、クラスター化インデックス (例:ORDER BY a, b, c) を使用する方が効果的です。この場合、ZORDER BYは使用しないでください。これは、ORDER BYが最初の列に対して優れたソートを提供し、後続の列への影響が少ないためです。対照的に、ZORDER BYは指定されたすべての列に均等な重みを与えるため、いずれか 1 つの列でのソートは、ORDER BY句の最初の列でのソートよりも効率が低くなります。特定の列が
JOINキーに頻繁に現れる場合は、ハッシュクラスタリングまたはレンジクラスタリングがより適しています。MaxCompute の Z オーダー実装はファイル内でのみデータをソートし、SQL エンジンは Z オーダーのデータ分布を認識しません。しかし、SQL エンジンはクラスター化インデックスを認識し、クエリプランフェーズでJOINパフォーマンスをより効果的に最適化できます。特定の列に対して
GROUP BYおよびORDER BY操作を頻繁に実行する場合、クラスター化インデックスを使用するとパフォーマンスが向上することがあります。
Zオーダーの推奨事項
フィルター条件に頻繁に現れる列、特に一緒によくフィルタリングされる列を選択します。
ZORDER BYに含める列が多いほど、個々の列に対するソートの効果は低くなります。したがって、4 列を超えて指定しないでください。列が 1 つしかない場合は、Z オーダーではなくクラスター化インデックスを使用してください。バランスの取れたカーディナリティ (個別値の数) を持つ列を選択します。性別列のような低カーディナリティの列は、ソートの利点が最小限です。ほとんどが一意の値を持つ高カーディナリティの列は、ソートコストを増加させます。なぜなら、MaxCompute の Z オーダー実装は、Z 値を計算するためにすべての個別値をメモリにキャッシュする必要があるためです。
テーブルサイズは小さすぎても大きすぎてもいけません。データ量が少なすぎる場合、Z オーダーの利点は明らかではありません。データ量が多すぎる場合、Z オーダーデータを生成するコストが高くなる可能性があり、ベースラインタスクの完了時間に大きな影響を与える可能性があります。