本記事は【 Advent Calendar 2025 】の19日目の記事です。 はじめに マイナビの2年目データエンジニアのItです 今回はSnowflakeデータベースに蓄積されるデータ(ACCOUNT_USAGEスキーマなど)を用いて、コストの可視化をしてみました。 背景 Snowflakeの利用者(主にビジネスサイドの人たち)に対してコストの可視化をし、コストの透明化を図りたいと考えていました。 「コストの可視化、そんなもんSnowsightで見ればいいでしょ!」 と言われてしまいそうなので、現在の条件を記載します。 マイナビはデータ利用者が denodo(仮想統合基盤) を経由してSnowflakeにアクセスします(マイナビの社員はdenodoのユーザアカウントを保持) 裏側の処理として、denodoは1つのSnowflakeのユーザアカウントでデータにアクセスします 利用者はSnowflakeのユーザアカウントを保持しないため、Snowsightにアクセスできません(もちろんコスト管理も確認できません) タグの作成 Snowflakeのタグ はKey-Value型で作成できます。今回はCOSTというキーに対して、部署名をバリューとして作成します。 --今回はTAG用のデータベースとスキーマを用意していますUSE DATABASE TAG;USE SCHEMA TAGS;CREATE TAG IF NOT EXISTS COST ALLOWED_VALUES 'ORG-1', 'ORG-2', 'ORG-3'; --今回はTAG用のデータベースとスキーマを用意しています USE DATABASE TAG; USE SCHEMA TAGS; CREATE TAG IF NOT EXISTS COST ALLOWED_VALUES ' ORG-1 ' , ' ORG-2 ' , ' ORG-3 ' ; タグの付与 ウェアハウスやスキーマに作成したタグを付与することにより、タグごとでコスト管理をすることができるようになります。 ALTER SCHEMA IF EXISTS DB-a.SCHEMA-1-A SET TAG TAG.TAGS.COST = 'ORG-1';ALTER SCHEMA IF EXISTS DB-a.SCHEMA-1-B SET TAG TAG.TAGS.COST = 'ORG-1';ALTER WAREHOUSE IF EXISTS WH-1-A SET TAG TAG.TAGS.COST = 'ORG-1';ALTER WAREHOUSE IF EXISTS WH-1-B SET TAG TAG.TAGS.COST = 'ORG-1'; ALTER SCHEMA IF EXISTS DB - a.SCHEMA - 1 - A SET TAG TAG.TAGS.COST = ' ORG-1 ' ; ALTER SCHEMA IF EXISTS DB - a.SCHEMA - 1 - B SET TAG TAG.TAGS.COST = ' ORG-1 ' ; ALTER WAREHOUSE IF EXISTS WH - 1 - A SET TAG TAG.TAGS.COST = ' ORG-1 ' ; ALTER WAREHOUSE IF EXISTS WH - 1 - B SET TAG TAG.TAGS.COST = ' ORG-1 ' ; SQLでの確認 利用するデータの確認 BIツールでの可視化の前に、公式ドキュメントを参考にどのようなテーブルが必要かを調べ、SQLでたたき台を作ります。以下のように、ウェアハウスやスキーマの情報とタグの情報をそれぞれ取得し、結合して出力します。 ウェアハウスの情報を WAREHOUSE_METERING_HISTORY から取得 スキーマの情報を SCHEMATA から取得 タグ情報を TAG_REFERENCES から取得 WITH schema_cost AS ( SELECT SCHEMA_ID, SUM(CREDITS_USED_CLOUD_SERVICES) AS TOTAL_CREDITS FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY WHERE START_TIME >= 'YYYY-MM-DD' AND END_TIME < 'YYYY-MM-DD' GROUP BY SCHEMA_ID),schema_info AS ( SELECT SCHEMA_ID, SCHEMA_NAME, CATALOG_NAME FROM SNOWFLAKE.ACCOUNT_USAGE.SCHEMATA),schema_tags AS ( SELECT OBJECT_ID, TAG_NAME, TAG_VALUE FROM SNOWFLAKE.ACCOUNT_USAGE.TAG_REFERENCES WHERE DOMAIN = 'SCHEMA'),warehouse_cost AS ( SELECT WAREHOUSE_ID, WAREHOUSE_NAME, SUM(CREDITS_USED) AS TOTAL_CREDITS FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY WHERE START_TIME >= 'YYYY-MM-DD' AND END_TIME < 'YYYY-MM-DD' GROUP BY WAREHOUSE_ID, WAREHOUSE_NAME),warehouse_tags AS ( SELECT OBJECT_ID, TAG_NAME, TAG_VALUE FROM SNOWFLAKE.ACCOUNT_USAGE.TAG_REFERENCES WHERE DOMAIN = 'WAREHOUSE')SELECT st.TAG_VALUE, 'SCHEMA' AS OBJECT_TYPE, SUM(sc.TOTAL_CREDITS) AS CREDITSFROM schema_cost scJOIN schema_info si ON sc.SCHEMA_ID = si.SCHEMA_IDJOIN schema_tags st ON sc.SCHEMA_ID = st.OBJECT_IDGROUP BY 1,2UNION ALLSELECT wt.TAG_VALUE, 'WAREHOUSE' AS OBJECT_TYPE, SUM(wc.TOTAL_CREDITS) AS CREDITSFROM warehouse_cost wcJOIN warehouse_tags wt ON wc.WAREHOUSE_ID = wt.OBJECT_IDGROUP BY 1,2ORDER BY 1,2; WITH schema_cost AS ( SELECT SCHEMA_ID, SUM (CREDITS_USED_CLOUD_SERVICES) AS TOTAL_CREDITS FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY WHERE START_TIME >= ' YYYY-MM-DD ' AND END_TIME < ' YYYY-MM-DD ' GROUP BY SCHEMA_ID ), schema_info AS ( SELECT SCHEMA_ID, SCHEMA_NAME, CATALOG_NAME FROM SNOWFLAKE.ACCOUNT_USAGE.SCHEMATA ), schema_tags AS ( SELECT OBJECT_ID, TAG_NAME, TAG_VALUE FROM SNOWFLAKE.ACCOUNT_USAGE.TAG_REFERENCES WHERE DOMAIN = ' SCHEMA ' ), warehouse_cost AS ( SELECT WAREHOUSE_ID, WAREHOUSE_NAME, SUM (CREDITS_USED) AS TOTAL_CREDITS FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY WHERE START_TIME >= ' YYYY-MM-DD ' AND END_TIME < ' YYYY-MM-DD ' GROUP BY WAREHOUSE_ID, WAREHOUSE_NAME ), warehouse_tags AS ( SELECT OBJECT_ID, TAG_NAME, TAG_VALUE FROM SNOWFLAKE.ACCOUNT_USAGE.TAG_REFERENCES WHERE DOMAIN = ' WAREHOUSE ' ) SELECT st.TAG_VALUE, ' SCHEMA ' AS OBJECT_TYPE, SUM (sc.TOTAL_CREDITS) AS CREDITS FROM schema_cost sc JOIN schema_info si ON sc.SCHEMA_ID = si.SCHEMA_ID JOIN schema_tags st ON sc.SCHEMA_ID = st.OBJECT_ID GROUP BY 1 , 2 UNION ALL SELECT wt.TAG_VALUE, ' WAREHOUSE ' AS OBJECT_TYPE, SUM (wc.TOTAL_CREDITS) AS CREDITS FROM warehouse_cost wc JOIN warehouse_tags wt ON wc.WAREHOUSE_ID = wt.OBJECT_ID GROUP BY 1 , 2 ORDER BY 1 , 2 ; SQL実行結果の確認 SQL実行結果の値がSnowsightのコスト管理の消費クレジットに対して大きな誤差がないかを確認します。 Snowsightのコスト管理のキャプチャは載せていませんが、誤差は数クレジットでした。そのため、今回のSQLで問題ないと判断しました。 誤差が生じる要因:WAREHOUSE_METERING_HISTORYテーブルのCREDITS_USED CREDITS_USEDはCREDITS_USED_COMPUTEとCREDITS_USED_CLOUD_SERVICESの合計であり、クラウドサービスの調整を考慮していないためです。(請求されるクレジットよりも大きくなる場合があります) https://docs.snowflake.com/ja/sql-reference/account-usage/warehouse_metering_history BIツールでの可視化 今回はTableau Prep Builderを用いてSQLで行ったことと同様の条件でデータ加工し、Tableau Desktopでダッシュボードを作りました。(詳細は省きます) ※ダッシュボード内の凡例について、厳密にはSCHEMAはストレージコストのみでもなく、WAREHOUSEもコンピューティングコストのみではありません まとめ Snowsightでコスト管理のほかにもガバナンス(Snowflakeのユーザやロール)やセキュリティ(トラストセンターやネットワークポリシー)なども確認できるため、SQLを書くことがないかもしれません。しかし、Snowflakeデータベースに蓄積されるデータを直接参照したいときも少なからずあると思います。 SnowsightのUIへの反映に数分かかるのでSQLで直ぐ確認したいときや、今回のようなBIツールで可視化したいといったときにはSQLやBIツールからSnowflakeデータベースを参照することになります。そういった際に少しでもACCOUNT_USAGEなどのSnowflakeデータベースについて知っておくと便利だと思います! Snowflakeを利用している方はぜひSQLでSnowflake内のデータを探索してみましょう 番外編:今回の開発における気付き こっそり、コストダッシュボードの開発した際の気付きについて残しておきます タグの粒度をシステム単位やテーブル単位のように小さくすることも検討したい ユーザにクレジット消費量の意識づけをし、より適切なコスト削減対策につながるのでは 使ってもらえるダッシュボードにするための工夫(定期的な周知など)も必要ですが… ユーザに対して、頻繁に使われているテーブルの紹介もできそう AWSのインフラ利用費などもSnowflakeのクレジット消費量に基づいた計算をしたい Tableau Exchangeに Tableau公式のSnowflakeコストダッシュボード がありました 実はダッシュボードをSharePointサイトに埋め込むためにPowerBIで作る予定でした…