試した理由
ユーザが過去ログを見る時に、データが多くてもDBの負荷を気にせず処理できて良いのではないか?と、思ったため。
また、料金的にも安くなるのでは?という期待感もあった。
試した結果
試したり試算した結果、クエリ課金が結構高くつくので不採用となった。
データ分析などの処理で実行時の料金なども含め、色々と把握してクエリを実行するのであればトータル安くなるのだろうが、ユーザが自由に検索した結果をページングで表示したりする用途には向かないという結論。
ここから下は調べた内容となる。
課金ポイント
- データ保持料金
- クエリ実行時料金
- steaming insert
- 数分単位でのバッチ処理でOKなど、リアルタイム性が不要であれば課金されない
ざっくりと算出したい場合は、下記で入力すれば出る。
データ保持料金について
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に使い勝手を寄せていく方向なんだろうなぁと思った次第です。