1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【snowflake】Cortex Analystに26時間燃やされて学んだウェアハウスのタイムアウト設定

1
Posted at

はじめに

ある朝、なんとなくSnowflakeで実行中クエリを確認したら、26時間半も走り続けているクエリが見つかりました。Cortex Analystが生成したSQLにJOIN条件が抜けており、巨大なCROSS JOINを延々と計算していたのが原因です。

「なぜキャンセルされなかったのか?」を調べたら、STATEMENT_TIMEOUT_IN_SECONDS のデフォルト値が 2日(172,800秒) だったというオチでした。

この記事では、同じ事故を防ぐためのSnowflakeクエリタイムアウト設定をまとめます。

この記事で分かること

  • なぜ暴走クエリが長時間止まらないのか(デフォルト値の罠)
  • ウェアハウスに10分タイムアウトを仕掛ける方法
  • 設定の3つのレベルと優先順位ルール

参考リンク

起きたこと:Cortex Analystのクエリが26時間半止まらなかった

事象を整理するとシンプルです。

  • Cortex Analystに自然言語で集計を依頼
  • 生成されたSQLにJOIN条件が無く、暗黙のCROSS JOIN(デカルト積)になっていた
  • INFORMATION_SCHEMA.QUERY_HISTORY で確認したら26時間30分走行中
  • インタラクティブ用ウェアハウスを終日占拠

SYSTEM$CANCEL_QUERY で手動停止しましたが、根本対策は「そもそも勝手に長時間走らせない」ことだと判断しました。

check_running_query.sql
-- 実行中のクエリを確認するクエリ
SELECT
  query_id,
  query_text,
  user_name,
  warehouse_name,
  start_time,
  DATEDIFF(second, start_time, CURRENT_TIMESTAMP) AS run_time_seconds
FROM TABLE(INFORMATION_SCHEMA.QUERY_HISTORY(
  END_TIME_RANGE_START => DATEADD(minute, -5, CURRENT_TIMESTAMP)
))
WHERE execution_status = 'RUNNING'
ORDER BY start_time;

なぜ26時間も放置されたのか

Snowflakeには STATEMENT_TIMEOUT_IN_SECONDS というパラメータがあり、これを超えて走るクエリは自動でキャンセルされます。問題は このデフォルトが172,800秒(=2日) ということ。

デフォルト2日のまま使っていると、JOIN漏れや無限ループ的なSQLが流れたとき、最悪48時間ぶんのクレジットが溶けます。XSウェアハウスでも軽視できる金額ではありません。

要するに、放置設定は「クレジットを2日かけて燃やす」設定と同義です。本番環境ではもっと短く絞るのが定石ですね。

対策:ウェアハウスに10分タイムアウトを仕掛ける

cortex analyst用ウェアハウスに 10分(600秒) のタイムアウトを設定します。10分はDWHの感覚だと長めに思うかもしれませんが、BIツールのアドホック分析やCortex Analyst由来のクエリではこれでも余裕があるくらいです。

set_timeout.sql
-- インタラクティブ用WHに10分タイムアウトを設定
ALTER WAREHOUSE INTERACTIVE_WH
  SET STATEMENT_TIMEOUT_IN_SECONDS = 600;

-- キュー待ちが5分を超えたらキャンセル(任意)
ALTER WAREHOUSE INTERACTIVE_WH
  SET STATEMENT_QUEUED_TIMEOUT_IN_SECONDS = 300;

STATEMENT_QUEUED_TIMEOUT_IN_SECONDS はキューに積まれたまま放置されることを防ぐパラメータで、デフォルトは0(無効)です。同時実行の多い環境では併用すると安全です。

設定が効いているか確認する

設定後は SHOW PARAMETERS で必ず反映を確認します。

check_parameters.sql
SHOW PARAMETERS LIKE 'STATEMENT%TIMEOUT%' IN WAREHOUSE INTERACTIVE_WH;

注目するのは level です。WAREHOUSE と表示されていればウェアハウス側の設定が効いています。空欄だとアカウントのデフォルトが使われている状態なので、ALTER文がうまく反映されていない可能性があります。

ひと工夫:3つのレベルを使い分ける

STATEMENT_TIMEOUT_IN_SECONDS は4つのレベルで設定可能ですが、運用上重要なのは アカウント・ウェアハウス・セッションの3つ です。

レベル コマンド 役割
アカウント ALTER ACCOUNT SET ... 全体の最終ライン
ウェアハウス ALTER WAREHOUSE xxx SET ... ワークロード別の制御
セッション ALTER SESSION SET ... 個別ジョブで一時的に上書き

複数レベルで設定された場合、最も小さい値が勝つ ルールです。アカウントが1時間、ウェアハウスが10分なら、10分でキャンセルされます。

推奨パターン

ワークロード別に段階的に設定するのが現実的です。

recommended_setup.sql
-- 1) アカウント全体の保険として1時間
ALTER ACCOUNT SET STATEMENT_TIMEOUT_IN_SECONDS = 3600;

-- 2) インタラクティブ用WHは10分
ALTER WAREHOUSE INTERACTIVE_WH
  SET STATEMENT_TIMEOUT_IN_SECONDS = 600;

-- 3) バッチ用WHは2時間(業務に応じて調整)
ALTER WAREHOUSE BATCH_WH
  SET STATEMENT_TIMEOUT_IN_SECONDS = 7200;

バッチ用WHにまで10分を適用すると、大規模MERGEや日次集計が巻き込まれてエラーになります。本番反映前に ACCOUNT_USAGE.QUERY_HISTORY で実行時間の分布を確認することをおすすめします。

キャンセルされたクエリを追跡する

タイムアウトでキャンセルされたクエリは error_message から検知できます。

track_timeout.sql
SELECT
  query_id,
  user_name,
  warehouse_name,
  total_elapsed_time / 1000 AS elapsed_sec,
  error_message,
  start_time
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE start_time >= DATEADD(day, -1, CURRENT_TIMESTAMP)
  AND error_message ILIKE '%timeout%'
ORDER BY start_time DESC;

ACCOUNT_USAGE は最大45分の遅延があるので、リアルタイムで追いたい場合は INFORMATION_SCHEMA.QUERY_HISTORY を使ってください。

まとめ

  • Snowflakeのクエリタイムアウトデフォルトは 2日。本番環境では必ず短く設定する
  • インタラクティブ用WHは10分、バッチ用WHは2時間程度を目安に分ける
  • アカウントレベルにも保険として1時間を設定しておく
  • 複数レベル設定したら 最小値が勝つ ルールを覚えておく

タイムアウトはコスト保護の最後の砦ですが、根本的にはコスト監視の仕組みも欲しいところです。次のステップとして Resource Monitor で月次クレジットの上限を設定しておくと、タイムアウトをすり抜けて積み上がるコスト増にも対応できます。

「AIにSQLを書かせる時代」は便利な反面、人間がレビューしないクエリが流れる頻度が増えるということでもあります。タイムアウトのような最低限のガードレールは、早めに仕込んでおいて損はありません。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?