サンプリングとは
BigQueryのサンプリングについて理解を深めたので記します。
サンプリングとは、すべてのレコードを対象にするまでもないが、任意に抽出したn%のレコードに対してクエリを適用したいときに使う技術です。
クエリの最後にTABLESAMPLE SYSTEM (N PERCENT)
(Nは小数でもOK)をつけることによってサンプリングの指示をすることができます。
cloud.google.com
主な使用用途として、Dataplexによる品質測定やデータプロファイルが挙げられます。
品質測定では、すべてのレコードでテストするには料金がかかりすぎるので、任意に抽出したレコードでテストを通過すれば全体で通過したと見なすという考えで使われます。
cloud.google.com
データプロファイルでは、標本の統計値を測定して母集団の統計値とする考えで使われています。
cloud.google.com
TerraformのDataplexの項目にもsampling_percentという設定項目があります。
registry.terraform.io
サンプリングに関する誤解
サンプリングは全体のレコードから指定した%のレコードを取得するものではありません。
それを示すために実験を行います。
まず50個のレコードを持つテーブルを用意します。
SELECT COUNT(*) FROM `sample-project.sample_dataset.sample_table` -- 50
このテーブルに対してTABLESAMPLE SYSTE
を使用しても結果は5ではなく、50のままです。
SELECT COUNT(*) FROM `sample-project.sample_dataset.sample_table` TABLESAMPLE SYSTEM (10 PERCENT) -- 50
この現象はなぜ起こるのかと言うと、サンプリング%はストレージブロックの割合を示しているからです。
下記の資料に書かれている通り、BigQueryのテーブル及びパーティションテーブルは1GBごとにストレージブロックに自動的に分けられています。
通常、BigQuery は、テーブルまたはテーブル パーティションが約 1 GB より大きい場合、ブロックに分割します。小さいテーブルは、1 つのデータブロックで構成されている場合があります。その場合、TABLESAMPLE 句はテーブル全体を読み取ります。サンプリングの割合がゼロより大きく、テーブルが空でない場合、テーブル サンプリングで常に結果が返されます。
cloud.google.com
上記の実験で使ったテーブルは50レコードと小さすぎるため、1つのストレージブロックの中に全レコードがあると考えられます。
そのため、「全体で1つのストレージブロックの中から、10%分のストレージブロックを選択して」と命令しても、対象は1つのストレージブロックのままだったというわけです。
サンプリングの料金は?
BigQueryはスキャンした分に応じて料金がかかります。
サンプリングの場合、抽出されたストレージブロック分のみがスキャンの対象になるようです。
パーティションをまたいでいても、スキャンしたブロック単位の料金となるようです。
ユーザーがクエリで物理領域に関して指定できる最小の単位がパーティションだと思っていましたが、サンプリングを使うと更に小さい単位であるブロックまでを抽出単位にすることが出来るようです。
ただ、ブロックはパーティションと違い、IDで指定することがは不可能なため、正確な物理領域の指定は出来ません。
下図のように赤い部分のみがスキャンされ、その分のスキャン料金が加算されるようです。(全体のうち50%が指定されるのか、パーティションがあった場合は、各パーティションのうち50%が指定されるのかは分かっていません。)
