増分書き込みの繰り返し実行、SQL ジョブ、および Tunnel インポートでは、各タスクごとに個別の出力ファイルが生成されます。時間の経過とともに、パーティションには数千もの 64 MB 未満の小ファイルが蓄積します。これによりクエリ性能が低下し、Pangu ストレージ(Apsara Distributed File System:ADFS)への負荷が増加します。小ファイルのマージは、これらのファイルを少数の大きなファイルに統合することで、クエリ性能を回復させます。
MaxCompute では、ほとんどのマージ処理が自動で実行されます。自動マージが継続的な書き込みペースに追いつかない場合にのみ、手動で MERGE SMALLFILES コマンドを実行してください。
仕組み
MaxCompute では、小ファイルの蓄積を制御するために以下の 2 つのメカニズムが用いられます。
自動マージ — ジョブの完了後、パーティション内のファイル数がしきい値を超えると、MaxCompute は Fuxi タスクを割り当てて小ファイルをマージします。デフォルトでは、1 つの Fuxi インスタンスが処理できる小ファイルの最大数は 100 個です。ジョブログ内の MergeTask エントリにより、自動マージが実行されたことを確認できます。また、MaxCompute は定期的にメタデータベースをスキャンし、ファイル数が多いテーブルまたはパーティションに対して小ファイルのマージを実行します。
手動マージ — データがテーブルに継続的に書き込まれ、自動マージが追いつかない場合は、書き込みジョブを停止し、手動で MERGE SMALLFILES コマンドを実行します。
制限事項
小ファイルのマージには計算リソースが消費されます。従量課金インスタンスでは、SQL の従量課金と同率で課金されます。料金の詳細については、「課金(従量課金)」をご参照ください。
MERGE SMALLFILESコマンドはトランザクションテーブルをサポートしていません。トランザクションテーブルのコンパクションを行う場合は、代わりに COMPACTION コマンドをご利用ください。
テーブル内のファイル数の確認
テーブルまたはパーティションに含まれるファイル数を確認するには、DESC EXTENDED コマンドを実行します。
構文
DESC EXTENDED <table_name> [PARTITION (<pt_spec>)];パラメーター
| パラメーター | 必須 | 説明 |
|---|---|---|
table_name | はい | 対象のテーブル名 |
pt_spec | いいえ | 対象のパーティション。形式:(partition_col1 = partition_col_value1, partition_col2 = partition_col_value2, ...) |
実行例の出力

上記の例では、odl_bpm_wfc_task_log テーブルについて、ファイル数が 3,607 個、合計サイズが 274 MB(287,869,658 バイト)、平均ファイルサイズが約 0.07 MB であることが示されています。このパーティションはマージの適切な候補です。
マージのタイミング:パーティション内のファイル数が 100 個を超え、かつ平均ファイルサイズが 64 MB を下回る場合、小ファイルのマージを行ってください。
小ファイルのマージ
SQL コマンドの使用
必要に応じて小ファイルをマージするには、以下のコマンドを実行します。
ALTER TABLE <table_name> [PARTITION (<pt_spec>)] MERGE SMALLFILES;マージ後の結果として、odl_bpm_wfc_task_log テーブルのファイル数は 3,607 個から 19 個へ減少し、ストレージ使用量は 274 MB から 37 MB へ削減されます。

デフォルトのパラメーター設定は、ほとんどのケースで有効です。必要に応じて、以下の SET パラメーターを用いてマージ動作を調整できます。
| パラメーター | 説明 | デフォルト |
|---|---|---|
odps.merge.cross.paths | パス間でのファイルマージを許可するかどうか。この値を true に設定すると、パス構造を変更せずに各パス内の小ファイルを個別にマージします。 | — |
odps.merge.smallfile.filesize.threshold | マージ対象となるファイルサイズの上限(MB 単位)。未設定の場合、グローバル変数 odps_g_merge_filesize_threshold(デフォルト:32 MB)が使用されます。上書きする場合は、32 より大きい値を指定してください。 | 32 MB |
odps.merge.maxmerged.filesize.threshold | マージ後の単一出力ファイルの最大サイズ(MB 単位)。この上限に達すると、新しい出力ファイルが作成されます。未設定の場合、グローバル変数 odps_g_max_merged_filesize_threshold(デフォルト:500 MB)が使用されます。上書きする場合は、500 より大きい値を指定してください。 | 500 MB |
odps.merge.max.filenumber.per.instance | 1 つのマージインスタンスが処理可能なファイル数の上限 | — |
odps.sql.mapper.merge.limit.size | Fuxi インスタンスが読み取るファイルの合計サイズの上限 | — |
PyODPS の使用
PyODPS を使用すると、マージタスクを非同期で送信できます。これは、前日のジョブによって生成された複数のパーティションをまとめてマージする際に便利です。
以下のすべての例では、odps.run_merge_files() を用いてパーティションごとに非同期マージタスクを送信し、その後すべてのタスクが完了するまで待機しています。
import os
from odps import ODPS
# 環境変数から認証情報を読み込みます。
# コード内に AccessKey ID や AccessKey Secret を直接記述しないでください。
o = ODPS(
os.getenv('ALIBABA_CLOUD_ACCESS_KEY_ID'),
os.getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
project='<your-project>',
endpoint='<your-endpoint>',
)
# <table_name> をご利用のテーブル名に置き換えます。
table_name = '<table_name>'
t = o.get_table(table_name)
# マージオプションを設定します。
hints = {'odps.merge.maxmerged.filesize.threshold': 256}
# 対象日付のパーティションごとに 1 つのマージタスクを送信します。
# <datetime> を対象日付(例:'20240101')に置き換えます。
insts = []
for partition in t.iterate_partitions(spec='ds=<datetime>'):
instance = o.run_merge_files(table_name, str(partition), hints=hints)
# この Logview URL を開き、「Waiting Queue」をクリックすると、マージジョブログを確認できます。
print(instance.get_logview_address())
insts.append(instance)
# すべてのマージタスクの完了を待機します。
for inst in insts:
inst.wait_for_completion()スクリプトを実行する前に、以下のプレースホルダーを置き換えてください。
| プレースホルダー | 説明 | 例 |
|---|---|---|
<your-project> | ご利用の MaxCompute プロジェクト名 | my_project |
<your-endpoint> | ご利用の MaxCompute エンドポイント | <your-region-endpoint> |
<table_name> | マージ対象のテーブル | my_log_table |
<datetime> | 対象パーティションの日付値 | 20240101 |
スクリプトを実行する前に、PyODPS をインストールしてください。インストール手順については、「PyODPS ドキュメント」をご参照ください。
実行例
データ安定性チェックにより、tbcdm.dwd_tb_log_pv_di テーブルのマージが必要であることが判明しました。メタデータテーブル tbcdm.dws_rmd_merge_task_1d をクエリすると、ほとんどのパーティションでファイル数が 1,000 個を超え、一部では 7,000 個を超えており、さらにいくつかのパーティションでは平均ファイルサイズが 1 MB を下回っていることが明らかになりました。

以下のコマンドを実行して小ファイルをマージします。
SET odps.merge.cross.paths=true;
SET odps.merge.smallfile.filesize.threshold=128;
SET odps.merge.max.filenumber.per.instance = 2000;
ALTER TABLE tbcdm.dwd_tb_log_pv_di PARTITION (ds='20151116') MERGE SMALLFILES;マージ後の結果:

次のステップ
COMPACTION — トランザクションテーブル内のデータをコンパクションします
課金(従量課金) — マージジョブの課金について理解します