排查 Prisma 错误
本指南讲解了你在使用 Supabase 时可能遇到的一些常见的 Prisma 错误。
🌐 This guide addresses common Prisma errors that you might encounter while using Supabase.
完整的错误列表可以在 Prisma 官方文档 中找到。
🌐 A full list of errors can be found in Prisma's official docs.
理解连接字符串参数:[ #start ]
🌐 Understanding connection string parameters: [#start]
和其他库不同,Prisma 让你可以通过在连接字符串后附加的特殊选项来配置它的设置。
🌐 Unlike other libraries, Prisma lets you configure its settings through special options appended to your connection string.
这些选项,称为“查询参数”,可以用来处理特定错误。
🌐 These options, called "query parameters," can be used to address specific errors.
1# Example of query parameters23connection_string.../postgres?KEY1=VALUE&KEY2=VALUE&KEY3=VALUE错误 #
🌐 Errors
预处理语句已存在 #
🌐 Prepared statement already exists
交易模式下的 Supavisor(端口 6543)不支持 预处理语句,而 Prisma 会在后台尝试创建它们。
🌐 Supavisor in transaction mode (port 6543) does not support prepared statements, which Prisma will try to create in the background.
解决方案:[已有准备好的声明]
🌐 Solution: [#solution-prepared-statement-exists]
- 在连接字符串中加入
pgbouncer=true。这会在 Prisma 中关闭预处理语句。
1.../postgres?pgbouncer=true无法连接到数据库服务器 #
🌐 Can't reach the database server
Prisma 在超时之前无法与 Postgres 或 Supavisor 建立连接。
🌐 Prisma couldn't establish a connection with Postgres or Supavisor before the timeout.
可能原因:#
🌐 Possible causes: [#possible-causes-cant-reach-database-server-at]
- 数据库过载:数据库服务器负载很重,导致 Prisma 连接困难。
- 连接字符串格式错误:Prisma 使用的连接字符串不正确或不完整。
- 临时网络问题:短暂的网络故障正在干扰连接。
解决方案:[无法连接到数据库服务器]
🌐 Solutions: [#solution-cant-reach-database-server-at]
- 检查数据库健康状况:使用 可观测性仪表板 监控 CPU、内存和 I/O 使用情况。如果数据库负载过高,可以考虑增加你的 计算资源 或 优化你的查询。
- 验证连接字符串:仔细检查你在 Prisma 配置中的连接字符串,确保它与你的 项目连接页面 上的匹配。
- 增加连接超时:尝试在你的 Prisma 配置中增加
connect_timeout参数,给它更多时间来建立连接。
1.../postgres?connect_timeout=30从连接池获取新连接超时了 #
🌐 Timed out fetching a new connection from the connection pool
Prisma 无法足够快地为待处理的查询分配连接来满足需求。
🌐 Prisma is unable to allocate connections to pending queries fast enough to meet demand.
可能原因:[#可能原因-获取新连接超时]
🌐 Possible causes: [#possible-causes-timed-out-fetching-a-new-connection]
- 服务器超载:托管 Prisma 的服务器负载很重,限制了它管理连接的能力。默认情况下,Prisma 会创建默认的
num_cpus * 2 + 1数量的连接。服务器压力增加的一个常见原因是将connection_limit大幅提高超过默认值。 - 池大小不足:Supavisor 连接池没有足够的连接来满足 Prisma 的请求。
- 慢查询:Prisma 的查询执行时间太长,导致不能及时释放连接以供重用。
解决方案:[#solution-timed-out-fetching-a-new-connection]
🌐 Solutions: [#solution-timed-out-fetching-a-new-connection]
- 增加连接池超时:在你的 Prisma 配置中增加
pool_timeout参数,给连接池分配连接更多的时间。 - 降低连接限制:如果你在 Prisma 配置中明确增加了
connection_limit参数,试着将其降低到一个更合理的值。 - 增加连接池大小:如果你正在使用 Supavisor 连接,尝试在数据库设置中增加连接池的大小。
- 优化查询:提升查询效率以减少执行时间。
- 增加计算能力:和前面的选项一样,这是一种减少查询执行时间的策略。
服务器已关闭连接 #
🌐 Server has closed the connection
根据这个 Prisma 的 GitHub 问题,这个错误可能和查询返回值太大有关,也可能是因为数据库负载太高导致的。
🌐 According to this GitHub Issue for Prisma, this error may be related to large return values for queries. It may also be caused by significant database strain.
解决方案:[#服务器已关闭连接]
🌐 Solutions: [#solution-server-has-closed-the-connection]
- 限制返回行数:尽量限制特别大的请求返回的总行数。
- 减少数据库压力:查看报表页面是否存在数据库压力。如果明显有压力,考虑优化或增加计算资源
检测到漂移:你的数据库模式与迁移历史不同步 #
🌐 Drift detected: Your database schema is not in sync with your migration history
Prisma 依赖迁移文件来确保你的数据库与 Prisma 的模型保持一致。外部的模式变更会被检测为“漂移”,Prisma 会尝试覆盖它们,这可能会导致数据丢失。
🌐 Prisma relies on migration files to ensure your database aligns with Prisma's model. External schema changes are detected as "drift", which Prisma will try to overwrite, potentially causing data loss.
可能原因:[#可能原因-你的数据库模式不同步]
🌐 Possible causes: [#possible-causes-your-database-schema-is-not-in-sync]
- Supabase 托管的模式:Supabase 可能会更新像 auth 和 storage 这样的托管模式,以引入新功能。授予 Prisma 对这些模式的访问权限可能会在更新时导致偏移。
- 外部模式修改:你的团队或其他工具可能在 Prisma 外修改了数据库模式,导致出现偏差。
解决方案:[#solution-your-database-schema-is-not-in-sync]
🌐 Solution: [#solution-your-database-schema-is-not-in-sync]
- 基线迁移:基线 会通过捕捉当前数据库模式来重新同步 Prisma,把它作为未来迁移的起点。
已达到最大客户端连接数 #
🌐 Max client connections reached
Postgres 或 Supavisor 拒绝了更多连接的请求
🌐 Postgres or Supavisor rejected a request for more connections
可能的原因:#
🌐 Possible causes:[#possible-causes-max-client-connections-reached]
- 在事务模式下工作时(端口 6543): 当客户端尝试与连接池建立的连接超过其支持的数量时,会出现“达到最大客户端连接数”的错误。
- 在会话模式下工作(端口 5432)时: 客户端的最大数量受限于 数据库设置 中的“连接池大小”值。如果“连接池大小”设置为 15,即使连接池管理器可以处理 200 个客户端连接,每个唯一的“数据库角色+数据库”组合仍然会被有效地限制为 15 个。
- 在使用直接连接时:Postgres 已经达到了最大连接数
解决方案 #
🌐 Solutions [#solutions-causes-max-client-connections-reached]
- 无服务器应用的事务模式:如果你在使用无服务器函数(Supabase Edge、Vercel、AWS Lambda),请切换到事务模式(端口 6543)。它能处理比会话模式或直接连接更多的连接数。
- 减少 Prisma 连接数量:一个客户端-服务器可以和连接池建立多个连接。通常,无服务器(serverless)设置不需要太多连接。一般从少量开始,比如五个、三个,甚至一个,通常就够了。在无服务器设置中,可以从
connection_limit=1开始,如果需要再小心增加,以避免连接数达到上限。 - 增加连接池大小:如果你正在使用 Supavisor 连接,尝试在数据库设置中增加连接池的大小。
- 适时断开连接:当不再需要 Prisma 连接时,请关闭它们。
- 减少查询时间:通过降低查询复杂度或为你的表添加策略性索引来加快查询速度。
- 增加计算规模:有时候最好的选择是增加你的计算规模,这也会提高你的最大客户端大小和查询执行速度
只有当目标 schema 被列在你的数据源的 schemas 属性中时,才允许跨 schema 引用 #
🌐 Cross schema references are only allowed when the target schema is listed in the schemas property of your data-source
Prisma 的迁移正在引用一个它不被允许管理的模式。
🌐 A Prisma migration is referencing a schema it is not permitted to manage.
可能的原因:[#可能原因-跨模式引用]
🌐 Possible causes: [#possible-causes-cross-schema-references]
- 一个迁移引用了 Prisma 不允许管理的模式
解决方案: #
🌐 Solutions: [#solutions-cross-schema-references]
- 多模式支持:如果外部模式不是由 Supabase 管理的,请在你的
schema.prisma文件的datasource块中列出相关模式。
1generator client {2 provider = "prisma-client"3 output = "../generated/prisma"4}56datasource db {7 provider = "postgresql"8 schemas = ["public", "other_schema"] //list out relevant schemas9}- Supabase 管理的模式:由 Supabase 管理的模式,比如
auth和storage,可能会为了支持新功能而发生变化。直接引用这些模式将来会导致模式漂移。最好在迁移中移除对这些模式的引用。
另一种引用这些表的策略是通过触发器将值复制到 Prisma 管理的表中。下面是一个将 auth.users 的值复制到名为 profiles 的表中的示例。
🌐 An alternative strategy to reference these tables is to duplicate values into Prisma managed table with triggers. Below is an example for duplicating values from auth.users into a table called profiles.
显示/隐藏详情
1-- Create the 'profiles' table in the 'public' schema2create table public.profiles (3 id uuid primary key, -- 'id' is a UUID and the primary key for the table4 email varchar(256) -- 'email' is a variable character field with a maximum length of 256 characters5);1-- Function to handle the insertion of a new user into the 'profiles' table2create function public.handle_new_user()3returns trigger4language plpgsql5security definer set search_path = ''6as $$7begin89 -- Insert the new user's data into the 'profiles' table10 insert into public.profiles (id, email)11 values (new.id, new.email);1213 return new; -- Return the new record14end;15$$;1-- Function to handle the updating of a user's information in the 'profiles' table2create function public.update_user()3returns trigger4language plpgsql5security definer set search_path = ''6as7$$8begin9 -- Update the user's data in the 'profiles' table10 update public.profiles11 set email = new.email -- Update the 'email' field12 where id = new.id; -- Match the 'id' field with the new record1314 return new; -- Return the new record15end;16$$;1-- Function to handle the deletion of a user from the 'profiles' table2create function public.delete_user()3returns trigger4language plpgsql5security definer set search_path = ''6as7$$8begin9 -- Delete the user's data from the 'profiles' table10 delete from public.profiles11 where id = old.id; -- Match the 'id' field with the old record1213 return old; -- Return the old record14end;15$$;1-- Trigger to run 'handle_new_user' function after a new user is inserted into 'auth.users' table2create trigger on_auth_user_created3 after insert on auth.users4 for each row execute procedure public.handle_new_user();56-- Trigger to run 'update_user' function after a user is updated in the 'auth.users' table7create trigger on_auth_user_updated8 after update on auth.users9 for each row execute procedure public.update_user();1011-- Trigger to run 'delete_user' function after a user is deleted from the 'auth.users' table12create trigger on_auth_user_deleted13 after delete on auth.users14 for each row execute procedure public.delete_user();