2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BigQueryAdvent Calendar 2024

Day 6

BigQueryのCTE(WITH句)をマテリアライズする方法

Last updated at Posted at 2024-12-06

この記事はBigQuery Advent Calendar 2024 6日目の記事です。

こんにちは、吉岡です。
この記事ではBigQueryのCTE(WITH句)をマテリアライズ化する方法を紹介します。

はじめに

BigQueryでは中間的なクエリ結果をCTEとして記述することができます。このCTEは通常マテリアライズ化されません。

GoogleSQL only materializes the results of recursive CTEs, but doesn't materialize the results of non-recursive CTEs inside the WITH clause. If a non-recursive CTE is referenced in multiple places in a query, then the CTE is executed once for each reference. The WITH clause with non-recursive CTEs is useful primarily for readability.
( GoogleSQLは再帰CTEのみマテリアライズ化し、非再帰のCTEではWITH句をマテリアライズ化しません。非再帰CTEが複数の場所で参照されると、そのCTEは参照される度に毎回実行されます。非再帰CTEは可読性を向上させるためのものです。)
https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#with_clause

しかし、これでは複雑なCTEや大規模なデータを集約した場合などで、無駄に何度も同じクエリを実行されることになります。

テーブルを作り明示的にマテリアライズ化することもできますが保存先を決める必要があり、また一時テーブルを利用するとクエリキャッシュが利用できなくなります。

そこで、再帰CTEを利用してみます。上記引用文のように再帰CTEはマテリアライズ化されます。再帰CTEにするためには"WITH RECURSIVE"と記述する必要がありますが、それだけでは再帰CTEとして扱われません。実際に自分自身のテーブルを参照する必要があります。

それでは試してみましょう。

通常のCTE(非再帰)

まず、通常のCTEで、with句のテーブルを複数回参照するクエリを実行してみます。
違いがわかりやすいように乱数を返すCTEを使ってみます。

with 
  cte as (
    select rand() as value
  )
select * from cte
union all
select * from cte

image.png

異なる乱数が表示され、CTEが2回実行されていることがわかります。

実行計画を見ても、rand()関数が二回呼び出されていることがわかります。

image.png

CTE(recursive指定)

次に"recursive"を指定してみましょう。

with recursive
  cte as (
    select rand() as value
  )
select * from cte
union all
select * from cte

image.png

やはり違う乱数が出力されます。単に"with recursive"と書くだけでは再帰CTEとして扱われないようです。

再帰CTE(自己参照)

そこで、"union all"で自分自身を参照してみます。実際に行が増えないように条件"where false"を指定してみます。

with recursive
  cte as (
    select rand() as value
    union all
    select * from cte where false
  )
select * from cte
union all
select * from cte

image.png

同じ乱数が出力されました! CTEがマテリアライズ化されているようです。

実行計画を見ても、計算を2回行うのではなく、計算結果が2回参照されているようです。

image.png

使い所

実際には、複数回CTEを実行した方が早いことも多いと思いますが、複雑なCTEや、大きいテーブルを集約した場合など、実行が速くなったりスロットが節約できることもあると思います。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?