0
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?

More than 3 years have passed since last update.

ログデータ処理でBigQueryを試したときの話

Last updated at Posted at 2021-10-05

試した理由

ユーザが過去ログを見る時に、データが多くてもDBの負荷を気にせず処理できて良いのではないか?と、思ったため。

また、料金的にも安くなるのでは?という期待感もあった。

試した結果

試したり試算した結果、クエリ課金が結構高くつくので不採用となった。

データ分析などの処理で実行時の料金なども含め、色々と把握してクエリを実行するのであればトータル安くなるのだろうが、ユーザが自由に検索した結果をページングで表示したりする用途には向かないという結論。

ここから下は調べた内容となる。

課金ポイント

  • データ保持料金
  • クエリ実行時料金
  • steaming insert
    • 数分単位でのバッチ処理でOKなど、リアルタイム性が不要であれば課金されない

ざっくりと算出したい場合は、下記で入力すれば出る。

GoogleCloudの料金計算ツール

データ保持料金について

Activeストレージと、LongTermストレージに分かれる。

90日間以上参照されているだけのテーブル or パーティションは自動的にそちらに移動となる。

料金が半額となるため、パーティション分割などで積極的に狙っていきたい。

こちらは恐れるほど高くはならない。

クエリ実行時料金について

おそらくこちらが高くなることが多いと思われる。

limit句、where句などで絞り込んだとしても、見に行った先にデータがあれば課金対象なので、

テーブル分割や、パーティション分割で絞り込んでおかないと料金が跳ね上がる。

クエリを書いたときは、dry run が出来るので、先に捜査されるデータ量を把握すると良いと思う。

  • select * from ... where id=1
    • 上記の場合、全カラムのバイト数 * 全レコード数
  • select name from ... where id=1
    • (nameカラムとidカラムのバイト数) * 全レコード数

day1回しか行わないなどでは問題ないが、検索などでクエリを連発すると厳しいことになる。

キャッシュヒットの場合は課金されないので、出来る限りキャッシュヒットする使い方を検討すると多少は費用を削減できる。

BigQuery におけるコスト最適化の ベスト プラクティス

Node.jsでのコード

index.ts

import * as bigquery from '@google-cloud/bigquery'

const datasetId = 'test_db'
const tableId = 'test_table'

async function main (): Promise<void> {
  await uploadData()
  await selectData()
}
main().catch(console.error)

function getClient (): bigquery.BigQuery {
  return new bigquery.BigQuery({ location: 'us-central1', autoRetry: false })
}

// データアップロード
async function uploadData (): Promise<void> {
  const bgClient = getClient()
  const metadata: bigquery.JobLoadMetadata = {
    sourceFormat: 'NEWLINE_DELIMITED_JSON',
    autodetect: false // autodetectがtrueだと、テーブルが無ければ勝手に作られる。
  }
  const result = await bgClient
    .dataset(datasetId)
    .table(tableId)
    .load('aaa.json', metadata) // 中身:{ "name": "nnn", "age": 25 }
  console.log(result[0].status)
}

// データ取得
async function selectData (): Promise<void> {
  const bgClient = getClient()
  const query = `SELECT *
                   FROM \`${datasetId}.${tableId}\`
                  LIMIT 100`

  // 基本0番目のやつしか使わないのに、なぜか配列でJobを返してくる。
  const jobs = await bgClient.createQueryJob({ query })

  const rows = await jobs[0].getQueryResults()

  rows.forEach((row) => console.log(row))
}

サンドボックスだとストリーミングインサートはエラーとなるので上記のloadを使った転送方式となっている。

前準備と実行

echo '{"name":"nnn","age":25}' > aaa.json
export GOOGLE_APPLICATION_CREDENTIALS="app-name-12345678.json"
ts-node --transpile-only index.ts

所感

今回の要件では採用を見送ったが、ドキュメントも日本語で揃っており、使いやすいなぁと思った。

触ってみてRDBMSを使ったことあるなら、サーバ実装などがあっても同じ感覚で作れるなぁという印象。

実際にDDLなんかも使えるようになっていて、SQLも標準SQLのほとんどが使用できるようになっているらしい。

Googleでの改良の方向性もRDBMSに使い勝手を寄せていく方向なんだろうなぁと思った次第です。

0
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
0
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?