はじめに:GA4のエクスポートは黙っていても増え続ける

GA4のBigQueryエクスポートを設定すると、events_YYYYMMDD という日付つきのテーブルが毎日ひとつずつ作られていきます。これ自体はとても便利な仕組みなのですが、ひとつ見落としがちな性質があります。それは「一度作られたテーブルは、誰かが消さないかぎり永遠に残り続ける」という点です。

最初の数か月は気になりません。けれど1年、2年と運用を続けると、テーブルの数は数百〜千件に達し、保存しているデータ量もじわじわと積み上がっていきます。BigQueryはクエリのスキャン量だけでなく、保存しているデータ量(ストレージ)にも課金されるため、使っていない古いデータを抱え込んだままだと、見えないところで固定費が増えていきます。

中小ECの規模だと月数百円〜数千円程度のことも多いのですが、「気づいたら何に払っているのか分からない費用」が残り続けるのは気持ちのいいものではありません。

もうひとつ厄介なのが、テーブルの数そのものが増えることによる「管理のしづらさ」です。データセットを開いたときに数百件のテーブルが並んでいると、どれが現役でどれが過去のものか一目では分かりません。掃除をしようにも、どこから手をつければいいのか判断がつかなくなります。

この記事では、こうしたテーブルの肥大化を自動で抑える「パーティション有効期限」の仕組みと設定方法を紹介します。仕組みを理解しておけば、最初に一度設定するだけで、あとはほぼ手を離して運用できるようになります。

ストレージ以外のコスト全般については、こちらの記事もあわせて読んでみてください。

まず押さえたい:GA4は「日付ごとにテーブルが分かれる」シャーディング

設定の話に入る前に、ひとつ大事な前提を整理しておきます。GA4のBigQueryエクスポートは、**1つの日付パーティションテーブルではなく、events_YYYYMMDD という名前で日付ごとにテーブルが分かれていく「日付シャーディング」**という方式です。

つまり events_20250101events_20250102…と、1日につき1つの独立したテーブルが積み上がっていきます。よく似た言葉に「日付パーティション」がありますが、これは1つのテーブルの中を日付で区切る別の仕組みで、GA4のエクスポートとは構造が違います。

ここを取り違えると設定の方針も変わってしまうので、まずは「GA4エクスポート=日付シャーディングされたテーブル群」と覚えておいてください。

古いGA4データを自動で消す2つの方法

シャーディングされたGA4テーブルを自動で整理したい場合、使うのは「パーティション有効期限」ではなく、次のどちらかです。

  • (a) データセットのデフォルトのテーブル有効期限analytics_<プロパティID> データセットにデフォルトのテーブル有効期限を設定しておくと、新しく作られる events_* テーブルに、その有効期限が自動で引き継がれます。GA4は毎日新しいテーブルを作るため、1件ずつ設定して回るより現実的です。
  • (b) 各テーブルの有効期限(expiration):個々の events_YYYYMMDD テーブルに対して、テーブル単位の有効期限を設定します。すでに溜まってしまった過去のテーブルを整理したいときは、こちらを使います。

どちらも「テーブルそのものを丸ごと消す」設定です。GA4のテーブルは1日1テーブルなので、テーブル単位で消えれば結果的にその日のデータが消える、という分かりやすい挙動になります。

ポイントは、手作業で古いテーブルを探して消す必要がなくなることです。「直近13か月分だけ残せば十分」といった運用方針が決まっていれば、(a)のデフォルト有効期限を一度設定するだけで、あとはBigQueryが古いテーブルを掃除し続けてくれます。

期限を過ぎたテーブルがいつ削除されるかには多少の幅がありますが、運用上は「設定した日数を超えたデータは順次消えていく」と捉えておけば十分です。細かな削除タイミングの仕様は変わることがあるため、厳密に把握したい場合は公式ドキュメントを確認してください。

「パーティション有効期限」が役立つのは自作テーブルのほう

なお partition_expiration_daysALTER TABLE ... SET OPTIONS で指定する設定)は、1つのテーブルの中を日付で区切った「日付パーティションテーブル」に対して、古いパーティション(区画)を自動削除する仕組みです。GA4が吐き出すシャードに対して個々に設定するものではありません。

この設定が効いてくるのは、GA4のデータをもとに自分で作る日付パーティション化したマートや中間テーブルです。たとえば「日次のサマリーテーブルを1つ作り、その中を event_date でパーティション分けする」といった構成では、パーティション有効期限を付けておくと古い区画だけが自動で消えてくれます。次の章ではこの自作テーブル向けの設定SQLを紹介します。

なぜ「自動で消える」がうれしいのか

手作業でテーブルを整理する運用には、地味につらいところがあります。月初めにカレンダーへ「古いテーブルを消す」とリマインダーを入れても、忙しいと後回しになりますし、消すべきテーブルを間違えるリスクもあります。

その点、有効期限による自動削除は「一度ルールを決めたら、あとは仕組みが守り続けてくれる」のが強みです。担当者が変わっても、リマインダーを見落としても、データの整理だけは淡々と続いていきます。属人的な運用から仕組みによる運用へ切り替える、という意味でも有効です。

設定する前に決めておくこと

設定そのものは一瞬で終わります。むしろ大事なのは、その前の「何日分残すか」という方針決めです。

  • 分析でよく振り返る期間はどれくらいか(前年同月比を見るなら最低13か月は必要、など)
  • 古いデータを消したあと、後から「やっぱり見たい」となったときに困らないか
  • 長期保存が必要なデータは別の場所に退避してあるか

このあたりを決めずにいきなり短い期限を設定すると、必要なデータまで消えてしまいます。後述しますが、消えたパーティションは基本的に元に戻せないと考えておくのが安全です。

設定SQL①:自作の日付パーティションテーブルに有効期限を付与する

まずは partition_expiration_days の使いどころ、つまり自分で作った日付パーティションテーブルへの設定から見ていきます。前章のとおり、これはGA4のシャードそのものではなく、GA4データから組み立てたマートや中間テーブルに対して効かせる設定です。

新しくパーティションテーブルを作る段階で設定しておきたい場合は、CREATE TABLE のオプションに含めます。

-- GA4データから作る日次サマリーを、event_date で日付パーティション化し、
-- 「365日」の有効期限を付ける例
CREATE TABLE `your_project.your_dataset.daily_summary`
(
  event_date DATE,
  source STRING,
  sessions INT64
)
PARTITION BY event_date
OPTIONS (
  partition_expiration_days = 365
);

すでにある日付パーティションテーブルに後から有効期限を設定するには、ALTER TABLE ... SET OPTIONS を使います。日数で指定する場合は partition_expiration_days を指定します。

-- 既存の日付パーティションテーブルに「540日(約18か月)」の有効期限を設定する例
ALTER TABLE `your_project.your_dataset.daily_summary`
SET OPTIONS (
  partition_expiration_days = 540
);

有効期限を解除して「無期限」に戻したいときは、NULL を設定します。

-- 有効期限を解除する
ALTER TABLE `your_project.your_dataset.daily_summary`
SET OPTIONS (
  partition_expiration_days = NULL
);

なお、オプション名や指定できる単位(日数指定か否か)は仕様変更の可能性があるため、本番に適用する前に最新の公式ドキュメントで確認してください。コンソールのテーブル詳細画面からも、現在の有効期限を確認・変更できます。

設定SQL②:GA4の events_ シャードへの適用と注意点

GA4のエクスポート先である analytics_<プロパティID> データセットには、events_* のほか events_intraday_*pseudonymous_users_* などのテーブルが含まれます。前章で見たとおりこれらは日付シャーディングされたテーブル群なので、パーティション有効期限ではなく、データセットのデフォルトのテーブル有効期限か、各テーブルの有効期限で整理します。

実運用でまず効くのが、(a)の「データセット単位のデフォルトのテーブル有効期限」です。これを設定しておくと、これから新しく作られる events_* テーブルに自動的に有効期限が引き継がれます。GA4のエクスポートは毎日新しいテーブルを作るため、テーブルを一つずつ設定して回るより、データセットのデフォルトを決めておくほうが現実的です。

-- データセットに「デフォルトのテーブル有効期限」を540日(約18か月)で設定する例
-- これ以降に作られる events_* テーブルに引き継がれる
ALTER SCHEMA `your_project.analytics_123456789`
SET OPTIONS (
  default_table_expiration_days = 540
);

注意したいのは、デフォルトのテーブル有効期限は設定後に作られるテーブルにしか効かない点です。すでに何年分も溜まっている過去のシャードには遡って適用されないため、こちらは(b)の「各テーブルの有効期限」で片付けます。

-- すでにある特定の events_ シャードに、テーブル単位の有効期限を設定する例
ALTER TABLE `your_project.analytics_123456789.events_20240101`
SET OPTIONS (
  expiration_timestamp = TIMESTAMP "2026-07-01 00:00:00 UTC"
);

過去分が大量にある場合は、INFORMATION_SCHEMA などで古いテーブル名を一覧し、整理用のクエリやスクリプトでまとめて有効期限を付けるか削除してから運用を始めると、状態がきれいに揃います。なお、データセットのデフォルトと個々のテーブルの設定の関係や、オプション名・指定単位は挙動が変わることがあるため、本番適用の前に公式ドキュメントで最新仕様を確認してください。

⚠️ 期限切れでデータは消える。元には戻らない前提で

ここがいちばん大事な注意点です。有効期限を過ぎたテーブル(やパーティション)のデータは自動的に削除され、原則として復元できません。

たとえば有効期限を90日に設定してしまうと、3か月より前のデータはどんどん消えていきます。前年同月比や季節トレンドの分析をしたくなったときに、肝心の過去データが残っていない、という事態になりかねません。

  • 「コスト削減」を急ぐあまり、短すぎる期限を設定しない
  • 設定を変える前に、現在どんな有効期限になっているかを必ず確認する
  • 重要な分析で参照する期間より、十分に余裕を持たせた日数にする
  • 本番に適用する前に、影響範囲をチームで共有しておく

削除は静かに進むため、間違いに気づくのは「あのデータを見たい」となった後になりがちです。最初は長めに設定しておき、運用しながら短くしていくくらいが安全です。

おすすめの期限の目安

具体的にどれくらいに設定すればいいのか、迷う方も多いと思います。あくまで一例ですが、中小ECなら次のような考え方が出発点になります。

  • 前年同月比や季節トレンドをきちんと見たいなら、最低でも13か月(約400日)は残す
  • 余裕を持たせるなら18か月〜24か月程度にしておくと、年をまたいだ比較でも困りにくい
  • 「直近の動きさえ追えればよい」割り切った運用なら、もっと短くしても構わない

大切なのは、自分たちが実際にどこまで過去を振り返るかという「分析の習慣」に合わせることです。誰も見ない3年前のデータを律儀に持ち続ける必要はありませんし、毎月のように見返すデータを消してしまっては本末転倒です。

長期保存が必要なデータはGCSやスナップショットへ

「コストは下げたいけれど、過去データも残しておきたい」という場合は、消す前に別の場所へ退避させる方法があります。

ひとつは、Cloud Storage(GCS)へのエクスポートです。古いテーブル(GA4のシャードや、自作マートのパーティション)をParquetやAvro、CSVなどの形式でGCSに書き出しておけば、BigQueryのテーブルからは消しても、ファイルとしては手元に残せます。GCSの保存単価はBigQueryのアクティブストレージより安い場合が多く、さらにアクセス頻度の低いデータ向けの保存クラスを使えば費用を抑えられます。必要になったら外部テーブルとして読み込み直すことも可能です。

もうひとつは、テーブルスナップショットです。ある時点のテーブルの状態を低コストで保存しておける仕組みで、元テーブルとの差分だけを保持するため、まるごとコピーするより安く済みます。「念のため一時点のバックアップを残してから古いデータを整理したい」といった用途に向いています。

どの方法を選ぶにしても、アーカイブの形式・保存クラス・外部テーブルからの読み込み手順は変わりやすい部分なので、実際の構成を組む前に公式ドキュメントで最新の仕様を確認しておくと安心です。

退避と削除をセットで運用するなら、「古いテーブルやパーティションをGCSへ書き出す → 書き出しが成功したことを確認する → そのうえで有効期限で消えるに任せる」という順番にしておくと安全です。退避の処理はスケジュールされたクエリやワークフローとして組んでおけば、ここも手作業から解放できます。

無料枠の範囲でストレージとクエリをやりくりする全体方針については、こちらの記事も参考になります。

まとめ

GA4のBigQueryエクスポートは便利な反面、events_YYYYMMDD のテーブルが毎日増え続けるため、放っておくとストレージ費用がじわじわ膨らみます。GA4のシャードはデータセットのデフォルトのテーブル有効期限やテーブル単位の有効期限で、自作の日付パーティションテーブルはパーティション有効期限で、それぞれ古いデータを自動で整理でき、肥大化を手間なく防げます。

設定そのものは ALTER SCHEMAALTER TABLE ... SET OPTIONS の一行で済みますが、本当に大事なのは「何日分残すか」という方針決めです。期限を過ぎたデータは原則として戻らないため、分析で振り返る期間を踏まえて余裕のある日数にすること、そして長期保存が必要なものはGCSやスナップショットへ退避させてから整理することを忘れないでください。

最後に、設定した後の運用についても一言だけ。有効期限は「設定して終わり」ではなく、半年に一度くらいは現在の設定値と実際のテーブル状況を見直すのがおすすめです。事業の成長に合わせて、見たい期間や残したいデータの範囲は少しずつ変わっていきます。そのときどきの分析の習慣に合わせて期限を調整していけば、ストレージは無駄なく、必要なデータはちゃんと手元に、という良いバランスを保てます。

「最初は長めに、運用しながら調整する」を基本に、見えないストレージ費用をすっきりさせていきましょう。