Closed12

Prisma+Supabase Postgres+VercelでDBへの接続が遅い

ピン留めされたアイテム
PlatPlat

環境変数、Prismaに与えるDBのURLはこれに従えば大丈夫そうだ:

https://supabase.com/partners/integrations/prisma

shcema.prisma
datasource db {
  provider          = "postgresql"
  url               = env("DATABASE_URL")
  directUrl         = env("DIRECT_URL")
}

このように DATABASE_URLDIRECT_URL を用意する。

問題はこの URL をどうするかだが、まずは DATABASE_URL の方を対処する。

Project Settings > Database > Connection string の URL をコピーするが、ここで「Mode: Transaction」になっていることを確認する。これは、Pooler 接続に Transaction モードを使うのだが、もう一方の Session と比較するとポート番号が異なる。Session は 5432 だが、Transaction は 6543 なので注意。

コピーしたら、記事のとおりになるように後ろの方にクエリを追加する

追加するのは

?pgbouncer=true&connection_limit=1

で、追加後は

postgres://[db-user].[project-ref]:[db-password]@aws-0-[aws-region].pooler.supabase.com:6543/[db-name]?pgbouncer=true&connection_limit=1

のようになる。大抵の場合は [db-user][db-name]postgres だろう。

DIRECT_URL の方は Session モードをを使うが、こちらは特に変更ないのでそのままコピーしたものを使えばいい。ちゃんとポートが 5432 なのをチェックすること。

こうなる:

postgres://[db-user].[project-ref]:[db-password]@aws-0-[aws-region].pooler.supabase.com:5432/[db-name]

これらを環境変数にセットして

.env
DATABASE_URL="" # Transaction モードの方
DIRECT_URL=""  # Session モードの方

完了。

PGBouncer が非推奨になってるのに ?pgbouncer=true をつけるのは何事かというと、新しい Supavisor はPGBouncerのときに使うモードと同じモードで接続しないといけないらしく、Prismaにそれを教えるために同じ表記をしているだけらしい。

?pgbouncer=true をつけないと prepared statement \"s0\" already exists とかいうエラーが出る。

connection_limit=1 の方は何かというと、Vercel とかのサーバーレス環境だと複数の接続が発生しやすくなっているため、こうしないとDBに負荷がかかってやばいらしい。基本的に 1 で大丈夫とのこと。

https://www.prisma.io/docs/orm/prisma-client/setup-and-configuration/databases-connections#serverless-environments-faas

ピン留めされたアイテム
PlatPlat

connection_limit=1 でいいらしいと書いたが、このままだとトランザクションを行うとうまくいかないことが多く発生してしまったので、connection_limit=3 に変更したらスムーズにトランザクションできるようになった。

ピン留めされたアイテム
PlatPlat

Vercel←→Supabase のDBのやりとりが激遅問題は、主にリージョンが原因だったみたいだ。

vercel.json をプロジェクトのルートに作成し、

{
  "regions": ["hnd1"]
}

として日本リージョンを強制 (Supabase の DB を Tokyo に置いたので)することで、通信時間が大幅に改善した。

参考:

PlatPlat

Supabase Postgres に Prisma で直で接続するときの Vercel の環境変数の書き方が謎

SuapabseでPGBouncerは非推奨になるらしいからSupavisorを使うらしい?

よくわからんままconnection_limit=1にして永遠にリクエストが返ってこない

PlatPlat

データの取得が馬鹿みたいに思いのは、もしかしてVercelのサーバー関数がアメリカにあるのにDBが日本にあるから??

PlatPlat

現状発生している問題は、

  • Vercelでデータ取得にかかる時間が長すぎる
  • Supabaseよくわからんけど connection_limit=1 をセットすると永遠にデータを取得できなくなる
PlatPlat

とりあえず、プロジェクト > Project Settings > Functions > Function Region がワシントンD.C.になってたので日本に変えた

PlatPlat

変わってくれた!!

データ取得が爆速になった!!

あやうくSupabaseのプロジェクトを破壊して作り直すところだった...

このスクラップは2024/04/01にクローズされました