🔚

Snowflakeの外部ステージでディレクトリを指定するときは末尾のスラッシュを忘れずに

2024/01/22に公開

前置き

こんにちは。さすらいのデータエンジニアのこみぃです。

Snowflakeには外部ステージという機能があり、以下のクラウドストレージを外部テーブルのような感じで参照できます。

  • AWS S3
  • Google Cloud Storage
  • Microsoft Azure

https://docs.snowflake.com/ja/user-guide/data-load-overview#external-stages

この機能は非常に便利なんですが、ちょっとした落とし穴を踏んだので、本日はそんなお話です。

起きたこと

今回起きていたのはAWS S3を外部ステージとしてしようした際にS3においてあるはずのファイルには入ってないレコードが大量にSELECTされたという感じでした。

S3に置いてあるparquetファイルには一切入っていないようなレコードが大量に出てきました。
やれやれまたcsvのセル内改行か、とか思いましたが、parquetなのでそれも考えにくい。

なーぜー?

原因

今回の原因はわかりやすくいうと外部ステージを作成した際のCREATEコマンドにありました。

今回使ったSQLはこんな感じ。テーブル名とかはサンプルですが、伝わるかと思います。

create_stage_sql
CREATE STAGE TEST_KOMIYAMA.TABLE_01
STORAGE_INTEGRATION = S3_TEST_KOMIYAMA_INTEGRATION
URL = 's3://test-komiyama-20240120/table_01'
file_format = (TYPE = PARQUET)

そして、snowsqlのLISTコマンドで確認したファイルの一覧はこんな感じでした。

list
>list @equip;
+--------------------------------------------------------------+------------+------------------------------+-------------------------------+
| name                                                         | size       | md5                          | last_modified                 |
|--------------------------------------------------------------+------------+------------------------------+-------------------------------|
| s3://test-komiyama-20240120/table_01/test_01.parquet         | 1145141919 | XXXXXXXXXXXXXXXXXXXXXXXXXX-2 | Fri, 19 Jan 2024 17:11:54 GMT |
| s3://test-komiyama-20240120/table_012/test_012.parquet       |     114514 | XXXXXXXXXXXXXXXXXXXXXXXXXX-1 | Fri, 19 Jan 2024 17:13:09 GMT |
+--------------------------------------------------------------+------------+------------------------------+-------------------------------+

なんとなくおわかりいただいたかと思います。

そう、 CREATE文でのURLの指定はパスの前方一致でファイルを読み込んでしまう 模様で、table_01というディレクトリを指定していたつもりが、table_012というディレクトリも読み込まれてしまっていました。

今回のものはサンプルっぽいディレクトリ名にしてますが、実際の現場でもGlueやDMSでRDSのデータをS3においているような場合だと、似たようなテーブル名のテーブル同士でこういうことが起こり得ます。

例えば以下みたいなケースですね。

  • users / userstatus
  • item / item_users

解決策

解決策としては非常に簡単で、ディレクトリを指定したい場合には最後のスラッシュをちゃんと入れればOK

create_stage_sql
CREATE STAGE TEST_KOMIYAMA.TABLE_01
STORAGE_INTEGRATION = S3_TEST_KOMIYAMA_INTEGRATION
URL = 's3://test-komiyama-20240120/table_01/'
file_format = (TYPE = PARQUET)

以下の最後のスラッシュを足そうという話ですね。

refinement_sql
URL = 's3://test-komiyama-20240120/table_01/'

今回のケースに限らず、何か起きたらLISTコマンドを使うというのを覚えておくのも損はないと思います。
https://docs.snowflake.com/ja/sql-reference/sql/list

調査に異常に時間がかかった原因

今回の件で、恥ずかしながら調査に数時間かかったのですが、「変なデータがあるんだったら読み込まれてるファイル一覧を出したらいいじゃん」というご意見もあると思います。それは正しい。

実は今回はファイル一覧はWEBコンソールであるSnowsightで確認していました。
しかし、何故かSnowsightでは table_012 の方のファイルが一覧に表示されていなかったのです。

多分Snowsightのバグです。。。。

まあ、多分こう書いておけば偉い人が直してくれるでしょう!!!

結論

さて、今回は2つの結論を得ることができました。

外部ステージで謎の現象が起きたらまずはlistを打て
Snowsightはたまに変な挙動をするので異常の調査にはSnowSQLを使え

結びの言葉

そんなわけで、こういうハマりポイントでハマるのは本当に時間の浪費で悔しかったので、せめてシェアすることで同じ悔しさを味わう方がいなくなってくれればと思います。

最後に一つ宣伝を。
GENDAデータチームではプロダクトのデータ解析や機械学習プロジェクトを推進できるデータサイエンティストを募集しています。
https://hrmos.co/pages/genda/jobs/1700006587045969926

興味がおありの方は、ぜひぜひご連絡ください。
また、データサイエンティスト以外でも、なんならデータ系以外の方でも、優秀な方を常に求めています。GENDAという会社に興味があれば、是非お声おかけください。

本日はこのあたりで。
それじゃあ、バイバイ!

Snowflake Data Heroes

Discussion