Prisma+Supabase Postgres+VercelでDBへの接続が遅い
環境変数、Prismaに与えるDBのURLはこれに従えば大丈夫そうだ:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
このように DATABASE_URL
と DIRECT_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]
これらを環境変数にセットして
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
で大丈夫とのこと。
connection_limit=1
でいいらしいと書いたが、このままだとトランザクションを行うとうまくいかないことが多く発生してしまったので、connection_limit=3
に変更したらスムーズにトランザクションできるようになった。
Vercel←→Supabase のDBのやりとりが激遅問題は、主にリージョンが原因だったみたいだ。
vercel.json
をプロジェクトのルートに作成し、
{
"regions": ["hnd1"]
}
として日本リージョンを強制 (Supabase の DB を Tokyo に置いたので)することで、通信時間が大幅に改善した。
参考:
Supabase Postgres に Prisma で直で接続するときの Vercel の環境変数の書き方が謎
SuapabseでPGBouncerは非推奨になるらしいからSupavisorを使うらしい?
よくわからんままconnection_limit=1にして永遠にリクエストが返ってこない
Pooler の Transaction mode のポートは 6543、Sessionモードは 5432
Vercelで使うときはどっちにすべきなんだ??
データの取得が馬鹿みたいに思いのは、もしかしてVercelのサーバー関数がアメリカにあるのにDBが日本にあるから??
現状発生している問題は、
- Vercelでデータ取得にかかる時間が長すぎる
- Supabaseよくわからんけど connection_limit=1 をセットすると永遠にデータを取得できなくなる
とりあえず、プロジェクト > Project Settings > Functions > Function Region がワシントンD.C.になってたので日本に変えた
なぜか設定しても変わらない
効くかわからんけど vercel.json
を書いてみる
{
"regions": ["hnd1"]
}
プロジェクト設定をオーバーライドできるらしい。hnd1
は東京。
他のリージョンはここから選べる:
変わってくれた!!
データ取得が爆速になった!!
あやうくSupabaseのプロジェクトを破壊して作り直すところだった...