mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
1 parent
05dfc56211
commit
a0e144b1a2
6 files changed
+596
No files matched your search
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title = "Disabling Prepared statements"
|
||||
github_url = "https://github.com/orgs/supabase/discussions/28239"
|
||||
date_created = "2024-07-28T15:32:23+00:00"
|
||||
topics = ["database", "supavisor"]
|
||||
keywords = ["prepared", "statements", "transaction", "mode", "disable"]
|
||||
---
|
||||
|
||||
### It is important to note that although the direct connections and Supavisor in Session mode support prepared statements, Supavisor in transaction mode does not.
|
||||
|
||||
## How to disable prepared statements for Supavisor in transaction mode
|
||||
|
||||
Each ORM or library configures prepared statements differently. Here are settings for some common ones. If you don't see yours, make a comment
|
||||
|
||||
# Prisma:
|
||||
|
||||
add ?pgbouncer=true to end of connection string:
|
||||
|
||||
```
|
||||
postgres://[db-user].[project-ref]:[db-password]@aws-0-[aws-region].pooler.supabase.com:6543/[db-name]?pgbouncer=true
|
||||
```
|
||||
|
||||
# Drizzle:
|
||||
|
||||
Add a prepared false flag to the client:
|
||||
|
||||
```ts
|
||||
export const client = postgres(connectionString, { prepare: false })
|
||||
```
|
||||
|
||||
# node postgres
|
||||
|
||||
[Just omit the "name" value in a query definition](https://node-postgres.com/features/queries#prepared-statements):
|
||||
|
||||
```ts
|
||||
const query = {
|
||||
name: 'fetch-user', // <--------- DO NOT INCLUDE
|
||||
text: 'SELECT * FROM user WHERE id = $1',
|
||||
values: [1],
|
||||
}
|
||||
```
|
||||
|
||||
# psycopg
|
||||
|
||||
set the [prepare_threshold](https://www.psycopg.org/psycopg3/docs/api/connections.html#psycopg.Connection.prepare_threshold) to `None`.
|
||||
|
||||
# asyncpg
|
||||
|
||||
Follow the recommendation in the [asyncpg docs](https://magicstack.github.io/asyncpg/current/faq.html#why-am-i-getting-prepared-statement-errors)
|
||||
|
||||
> disable automatic use of prepared statements by passing `statement_cache_size=0` to [asyncpg.connect()](https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.connection.connect) and [asyncpg.create_pool()](https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool) (and, obviously, avoid the use of [Connection.prepare()](https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.connection.Connection.prepare));
|
||||
|
||||
# Rust's Deadpool or tokio-postgres:
|
||||
|
||||
- Check [Github Discussion](https://github.com/bikeshedder/deadpool/issues/340#event-13642472475)
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title = 'Error: prepared statement "XXX" already exists'
|
||||
github_url = "https://github.com/orgs/supabase/discussions/17751"
|
||||
date_created = "2023-09-27T09:53:08+00:00"
|
||||
topics = ["database"]
|
||||
keywords = ["pgbouncer", "prepared", "connection"]
|
||||
|
||||
[[errors]]
|
||||
message = 'prepared statement "XXX" already exists'
|
||||
---
|
||||
|
||||
This error occurs when you are trying to connect to the database using PgBouncer. PgBouncer does not support prepared statements. If you have prepared statements in use, you will need to use direct connections - port 5432.
|
||||
|
||||
There is a special parameter in the query string for Prisma to work with PgBouncer
|
||||
https://www.prisma.io/docs/guides/performance-and-optimization/connection-management/configure-pg-bouncer
|
||||
@@ -0,0 +1,187 @@
|
||||
---
|
||||
title = "Prisma Error Management"
|
||||
github_url = "https://github.com/orgs/supabase/discussions/27395"
|
||||
date_created = "2024-06-19T19:51:23+00:00"
|
||||
topics = ["database"]
|
||||
keywords = ["prisma", "timeout", "connection", "pgbouncer", "schema", "migration"]
|
||||
|
||||
[[errors]]
|
||||
message = "Can't reach database server at"
|
||||
|
||||
[[errors]]
|
||||
message = "Timed out fetching a new connection from the connection pool"
|
||||
|
||||
[[errors]]
|
||||
message = 'prepared statement "" already exists'
|
||||
|
||||
[[errors]]
|
||||
message = "Max client connections reached"
|
||||
|
||||
[[errors]]
|
||||
message = "Server has closed the connection"
|
||||
|
||||
[[errors]]
|
||||
message = "Drift detected: Your database schema is not in sync with your migration history"
|
||||
---
|
||||
|
||||
> This guide has been deprecated. Please use the troubleshooting guide in the [Supabase docs](https://supabase.com/docs/guides/database/prisma/prisma-troubleshooting).
|
||||
|
||||
# Addressing Specific Errors:
|
||||
|
||||
Prisma, unlike other libraries, uses [query parameters for configurations](https://www.prisma.io/docs/orm/overview/databases/postgresql#arguments).
|
||||
|
||||
Some can be used to address specific errors and can be appended to end of your connection string like so:
|
||||
|
||||
```md
|
||||
.../postgres?KEY1=VALUE&KEY2=VALUE&KEY3=VALUE
|
||||
```
|
||||
|
||||
## `Can't reach database server at`:
|
||||
|
||||
Increase `connect_timeout` to 30s and check to make sure you are using a valid connection string.
|
||||
|
||||
```md
|
||||
.../postgres?connect_timeout=30
|
||||
```
|
||||
|
||||
## `Timed out fetching a new connection from the connection pool`:
|
||||
|
||||
Increase `pool_timeout` to 30s .
|
||||
|
||||
```md
|
||||
.../postgres?pool_timeout=30
|
||||
```
|
||||
|
||||
## `... prepared statement "" already exists`
|
||||
|
||||
Add pgbouncer=true to the connection string.
|
||||
|
||||
```md
|
||||
.../postgres?pgbouncer=true
|
||||
```
|
||||
|
||||
## `Max client connections reached`
|
||||
|
||||
Checkout this [guide](https://github.com/orgs/supabase/discussions/22305) for managing this error
|
||||
|
||||
## `Server has closed the connection`
|
||||
|
||||
According to this [GitHub Issue for Prisma](https://github.com/prisma/prisma/discussions/7389), it may be related to large return values for queries. Try to limit the total amount of rows returned for particularly large requests.
|
||||
|
||||
## `Drift detected: Your database schema is not in sync with your migration history`
|
||||
|
||||
Prisma will try to act as the source of truth for your database structures. If you `CREATE`, `DROP`, or `ALTER` database objects outside of a Prisma Migration, it is likely to detect drift and may offer to correct the situation by purging your schemas. To circumvent this issue, try [baselining your migrations](https://www.prisma.io/docs/orm/prisma-migrate/workflows/baselining).
|
||||
|
||||
Some users have discussed how they managed this problem in a [GitHub Discussion.](https://github.com/prisma/prisma/issues/19100#top)
|
||||
|
||||
# Management Suggestions
|
||||
|
||||
## Make a custom role for Prisma to increase observability
|
||||
|
||||
**Imagine your database as a house, and users as the people with keys.**
|
||||
|
||||
- By default, most developers use the "master key" (the `postgres` role) to access everything. But it's safer to give Prisma its own key! This way, it can only access the rooms (tables) it needs.
|
||||
- it's usually safer to give Prisma its own key! This way, it can only access the rooms (tables) it needs.
|
||||
- Plus, with separate keys, it's easier to see what Prisma is doing in your house with monitoring tools, such as [PGAudit](https://supabase.com/docs/guides/database/extensions/pgaudit?queryGroups=database-method&database-method=sql) and [pg_stat_activity](https://supabase.com/docs/guides/platform/performance).
|
||||
|
||||
### Creating the Prisma User:
|
||||
|
||||
```sql
|
||||
create user "prisma" with password 'secret_password' bypassrls createdb;
|
||||
```
|
||||
|
||||
> Prisma requires the [createdb modifier](https://supabase.com/blog/postgres-roles-and-privileges#role-attributes) to create shadow databases. It uses them to help manage migrations.
|
||||
|
||||
### Give Postgres Ownership of the New User:
|
||||
|
||||
This allows you to view Prisma migration changes in the [Dashboard](https://supabase.com/dashboard/project/_/editor)
|
||||
|
||||
```sql
|
||||
grant "prisma" to "postgres";
|
||||
```
|
||||
|
||||
### Keep it safe!
|
||||
|
||||
Use a strong password for Prisma. Bitwarden provides a free and simple [password generator](https://bitwarden.com/password-generator/) that can make one for you.
|
||||
|
||||
If you need to change it later, you can use the below SQL:
|
||||
|
||||
```sql
|
||||
alter user "prisma" with password 'new_password';
|
||||
```
|
||||
|
||||
### Grant Prisma Access
|
||||
|
||||
The below example gives Prisma full authority over all database objects in the public schema:
|
||||
|
||||
```sql
|
||||
-- Grant it necessary permissions over the relevant schemas (public)
|
||||
grant usage on schema public to prisma;
|
||||
grant create on schema public to prisma;
|
||||
grant all on all tables in schema public to prisma;
|
||||
grant all on all routines in schema public to prisma;
|
||||
grant all on all sequences in schema public to prisma;
|
||||
alter default privileges for role postgres in schema public grant all on tables to prisma;
|
||||
alter default privileges for role postgres in schema public grant all on routines to prisma;
|
||||
alter default privileges for role postgres in schema public grant all on sequences to prisma;
|
||||
```
|
||||
|
||||
> For more guidance on specifying access, check out this [article](https://supabase.com/blog/postgres-roles-and-privileges#creating-objects-and-assigning-privileges) on privileges
|
||||
|
||||
## Optimize Prisma Queries:
|
||||
|
||||
In the [Query Performance Advisor](https://supabase.com/dashboard/project/_/database/query-performance), you can view long-running or frequently accessed queries by role:
|
||||
|
||||
<img
|
||||
width="1509"
|
||||
alt="Screenshot 2024-06-19 at 1 25 16 PM"
|
||||
src="https://github.com/supabase/supabase/assets/91111415/46e2feae-9fca-4436-a957-2c995eb5ca92"
|
||||
/>
|
||||
|
||||
Selecting a query can reveal suggestions to improve its performance
|
||||
|
||||
## Configuring Connections
|
||||
|
||||
Useful Links:
|
||||
|
||||
- [How to Monitor Connections and Find the Correct Pool Size](https://github.com/orgs/supabase/discussions/27141).
|
||||
- [Supavisor FAQ](https://github.com/orgs/supabase/discussions/21566)
|
||||
|
||||
Supabase provides 3 connection strings in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database). You can use all three or just the ones most relevant to your project.
|
||||
|
||||
### Direct Connection:
|
||||
|
||||
Best used with stationary servers, such as VMs and long-standing containers, but it only works in IPv6 environments unless the [IPv4 Add-On](https://supabase.com/dashboard/project/_/settings/addons) is enabled. If you are unsure if your network is IPv6 compatible, [check here](https://github.com/orgs/supabase/discussions/27034).
|
||||
|
||||
```md
|
||||
# Example Connection
|
||||
|
||||
postgresql://postgres:[PASSWORD]@db.[PROJECT REF].supabase.co:5432/postgres
|
||||
```
|
||||
|
||||
### Supavisor in Session Mode (port 5432):
|
||||
|
||||
```md
|
||||
# Example Connection
|
||||
|
||||
postgres://[DB-USER].[PROJECT REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres
|
||||
```
|
||||
|
||||
An alternative to direct connections when working in IPv4-only environments.
|
||||
|
||||
> Session mode is a good option for migrations
|
||||
|
||||
### Supavisor in Transaction Mode (port 6543):
|
||||
|
||||
```md
|
||||
# Example Connection
|
||||
|
||||
postgres://[DB-USER].[PROJECT REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres
|
||||
```
|
||||
|
||||
Should be used when deploying to:
|
||||
|
||||
- Horizontally auto-scaling servers
|
||||
- Edge/Serverless deployments
|
||||
|
||||
When working in serverless/edge environments, it is recommended to set the `connection_limit=1` and then gradually increase it if necessary.
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title = "Supavisor and Connection Terminology Explained"
|
||||
github_url = "https://github.com/orgs/supabase/discussions/27388"
|
||||
date_created = "2024-06-19T15:56:26+00:00"
|
||||
topics = ["supavisor", "database"]
|
||||
keywords = ["connections", "pooler", "transaction", "session", "pgbouncer"]
|
||||
---
|
||||
|
||||
I'll be the first to admit that the official naming conventions in the Postgres community can be a bit confusing, so here's a basic rundown. It's a bit long, so feel free to just jump to the portion relevant to you:
|
||||
|
||||
## Clients:
|
||||
|
||||
This is any server trying to connect to the pooler or database. This can be confusing because the term client in other scenarios also means users connecting through a frontend.
|
||||
|
||||
## Client connections:
|
||||
|
||||
A single application server can create multiple connections. A client connection represents any connection established by a server to the pooler.
|
||||
|
||||
## Direct/database connections:
|
||||
|
||||
This represents a direct connection to the database.
|
||||
|
||||
Your application servers can directly connect using the db connection string:
|
||||
|
||||
```md
|
||||
postgresql://postgres:[PASSWORD]@db.[PROJECT REF].supabase.co:5432/postgres
|
||||
```
|
||||
|
||||
When connecting through the pooler, it will establish db/direct connections on behalf of clients. It then forwards/triages requests from client connections to db/direct connections.
|
||||
|
||||
## max_connections:
|
||||
|
||||
Configured with the max_connections system variable, it represents how many direct/database connections postgres will tolerate. You can view your instance's settings by running this SQL:
|
||||
|
||||
```sql
|
||||
SHOW max_connections;
|
||||
```
|
||||
|
||||
To know more about configuring this value, check out [monitoring connections troubleshooting guide.](https://github.com/orgs/supabase/discussions/27197)
|
||||
|
||||
## Pool size:
|
||||
|
||||
The number of direct connections Supavisor is permitted to request from the database to manage each [database/role/mode combination](https://github.com/orgs/supabase/discussions/21566).
|
||||
|
||||
## Transaction mode:
|
||||
|
||||
Transaction mode gives the pooler permission to share direct connections among multiple clients. It is used when the pooler connection string is listening on port 6543:
|
||||
|
||||
```md
|
||||
#example transaction mode string
|
||||
postgres://postgres.obfwhevidiamwdwki:[YPASSWORD]@aws-0-ca-central-1.pooler.supabase.com:**6543**/postgres
|
||||
```
|
||||
|
||||
Postgres connections use the Postgres Wire Protocol (PWP) rather than HTTP. PWP acts like a websocket: once a connection is made, it stays open and active until the client disconnects.
|
||||
|
||||
If too many connections are held by idle or greedy clients, other application servers won’t be able to connect to your database. Transaction mode helps avoid this problem by allowing clients to access the database connections only when they are running a query. This reduces the chances of hitting the maximum direct connection limit.
|
||||
|
||||
## Session mode:
|
||||
|
||||
session mode restricts the pooler, forcing it to grant an underlying direct connection exclusively to a single client connection.
|
||||
|
||||
```md
|
||||
#example session mode string | uses port 5432
|
||||
postgres://postgres.obfwhevidiamwdwki:[YPASSWORD]@aws-0-ca-central-1.pooler.supabase.com:**5432**/postgres
|
||||
```
|
||||
|
||||
Session mode behaves nearly identically to a standard direct connection, which makes one wonder: what is the point?
|
||||
|
||||
One benefit is that if you need long-lasting connections in an IPv4-only environment and do not want to enable the IPv4 Add-On, session mode resolves this issue.
|
||||
|
||||
Another clear benefit is queueing. If all direct connections were taken, without the pooler, the n+1 client that tried to connect would be rejected. It would have to constantly poll the database to see if a slot became available. The pooler in session mode will queue a client for up to a minute, so it doesn't have to constantly poll while waiting for a slot.
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
title = "Supavisor FAQ"
|
||||
github_url = "https://github.com/orgs/supabase/discussions/21566"
|
||||
date_created = "2024-02-26T16:23:40+00:00"
|
||||
topics = ["supavisor", "database"]
|
||||
keywords = ["pooler", "connections", "supavisor", "database"]
|
||||
---
|
||||
|
||||
### What Problems Do Poolers Solve?
|
||||
|
||||
PostgreSQL stands out from other databases by opting to create a new process, not a new thread, for each direct connection. While this design choice brings [numerous benefits](https://www.postgresql.org/message-id/1098894087.31930.62.camel@localhost.localdomain), it introduces a startup penalty for new connections. Moreover, connections are more memory-intensive and can strain Postgres's internal schedulers, limiting the sustainable number that can be formed. Resultingly, developers must be mindful of how they allocate the resource.
|
||||
|
||||
When a client (backend server) connects to PostgreSQL, the connection is stateful and enduring, allowing clients to greedily hold onto connections without any obligation to give them up. Typically, applications do not continuously send queries to a database, so this pattern underutilizes finite connections that could have serviced other clients.
|
||||
|
||||
PostgreSQL's shortcomings are particularly evident when handling transient servers, like edge functions. They not only hoard connections for brief queries but also aggressively open and close connections, straining the database.
|
||||
|
||||
### How Do Poolers Solve the Problem?
|
||||
|
||||
A pooler is ultimately a load balancer for database connections. It maintains several hot connections that it triages to clients. This reduces the startup cost of creating a new process on Postgres. The pooler can also more efficiently manage a database's finite connections by only allowing clients to access them when they need to execute a query (A.K.A. transaction mode).
|
||||
|
||||
### Are Poolers Necessary?
|
||||
|
||||
All database connection libraries, such as Prisma, SQLAlchemy, and Postgres.js have built-in poolers. These are known as application-side poolers and they are fundamental for sustainable connection management. Most libraries have default pool sizes that may need to be changed for specific workloads. As an example, most edge/serverless functions are called to service a single user's request. They usually require significantly fewer connections (often 1 is optimal) than a dedicated application server.
|
||||
|
||||
Note, that like databases, servers can only maintain a certain amount of connections themselves. If you were to increase the number aggressively, the server may not be able gracefully orchestrate them. For instance, Prisma's [default pool size](https://www.prisma.io/docs/orm/prisma-client/setup-and-configuration/databases-connections/connection-pool#connection-pool-size) is automatically set to one more than twice the server's CPU count (1 + 2 \* num_of_CPUs). The Prisma Team chose this value because it is generally performant with ORM's internal architecture.
|
||||
|
||||
When deploying to static architecture, such as long-standing containers or VMs, application-side poolers are satisfactory on their own.
|
||||
|
||||
When connecting to your application from serverless/edge functions, horizontally auto-scaling servers, or in cases where you simply need more connections than what the database can manage, it's best to complement application-side poolers with a serverside one. Supabase provides Supavisor as an option, but you could use alternatives, such as Prisma's Accelerate or Cloudflare's Hyperdrive.
|
||||
|
||||
They sit between the database and your client servers. They are solely optimized for sustaining high numbers of client connections and queuing and triaging queries to the database. Although they add network complexity, they are necessary when managing auto-scaling servers that can hypothetically form an infinite amount of connections.
|
||||
|
||||
### Where are the connection strings
|
||||
|
||||
Supabase provides 3 database connection strings that can be used simultaneously if necessary. All can be viewed in the connection string section of the [Database Settings](https://supabase.com/dashboard/project/_/settings/database)
|
||||
|
||||
<img
|
||||
width="999"
|
||||
alt="Screenshot 2024-07-04 at 10 40 38 AM"
|
||||
src="https://github.com/supabase/supabase/assets/91111415/1d653203-84d9-406a-a7c9-1f7d097f5a29"
|
||||
/>
|
||||
|
||||
#### Direct connections:
|
||||
|
||||
> "Note uses an IPv6 address by default. [Check here to see if your network is IPv6 compatible](https://github.com/orgs/supabase/discussions/27034)"
|
||||
|
||||
```sh
|
||||
# Example connection string
|
||||
postgresql://postgres:[YOUR-PASSWORD]@db.ajrbwkcuthywfihaarmflo.supabase.co:5432/postgres
|
||||
```
|
||||
|
||||
#### Supavisor in transaction mode (port 6543)
|
||||
|
||||
```sh
|
||||
# Example transaction string
|
||||
postgresql://postgres.ajrbwkcuthywddfihrmflo:[YOUR-PASSWORD]@aws-0-us-east-1.pooler.supabase.com:6543/postgres
|
||||
```
|
||||
|
||||
#### Supavisor in session mode (port 5432)
|
||||
|
||||
```sh
|
||||
# Example session string
|
||||
postgresql://postgres.ajrbwkcuthywfddihrmflo:[YOUR-PASSWORD]@aws-0-us-east-1.pooler.supabase.com:5432/postgres
|
||||
```
|
||||
|
||||
### Supavisor: Transaction Mode vs. Session Mode?
|
||||
|
||||
When a client forms a direct connection with PostgreSQL, it usually will make a few queries, but may not utilize the connection the entire time. In transaction mode, a client is allowed to make a single query before being sent back to the figurative "waiting room". This prevents greedy or sedentary clients from hoarding connections. In most cases, this increases query throughput and is optimal.
|
||||
|
||||
In session mode, once the pooler assigns a direct connection, it stays with that client until voluntarily surrendered.
|
||||
|
||||
This behavior mirrors a direct connection, allowing greedy clients to monopolize the pool. This raises a question: what is the purpose of session mode?
|
||||
|
||||
Depending on your application's configurations, having the pooler manage a queue of patient clients is preferable to the alternative of constantly polling the database to check for an available connection. Session mode can queue clients for up to a minute. If this isn't particularly relevant to your application design, then the primary benefit is that it is [IPv4 compatible](https://github.com/orgs/supabase/discussions/27034). Also, unlike transaction mode, it supports prepared statements.
|
||||
|
||||
### What Happens when a Client Library, such as Prisma, Connects through Supavisor?
|
||||
|
||||
When clients connect to either PostgreSQL or Supavisor, they do so with the PostgreSQL Wire Protocol. Because of this, clients treat connections with pooler as if they were directly connected to PostgreSQL. The pooler then smoothly acts as a messenger between the database and the client.
|
||||
|
||||
### What are "Client Connections"?
|
||||
|
||||
TL;DR: They have nothing to do with front-end clients. They are the amount of backend-server connections that can connect to a serverside pooler.
|
||||
|
||||
Imagine a chess tournament with 60 boards. Each board represents a connection in a database. When a player sits down at a board, it's like a client connecting to the database. They can take their time with their moves or just sit there, not making any.
|
||||
|
||||
But when the tournament fills up and all the boards are taken, new players are turned away, and told to check back at a later time to see if a table becomes available.
|
||||
|
||||
Now, imagine the tournament organizers decide to expand the venue to house 200 people without adding more tables. Even when all boards are occupied, players don't have to leave. They can wait in the wings, and the moment a board opens up, someone from the waiting area can take their place. Likewise, if someone ends their game, but wants to play again, they can just go back to the waiting area. The waiting area represents the "Max Client Connections". Ultimately, the additional capacity provided by the pooler ensures fewer people are turned away from the "tournament".
|
||||
|
||||
### In the Context of Supavisor, what Does "pool size" Mean?
|
||||
|
||||
"Pool size" refers to the maximum number of direct connections the pooler can maintain per unique user, database, and mode combination. You can adjust it in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database) to strike a balance between efficient resource utilization and accommodating peak traffic.
|
||||
|
||||
### What is the "user+db+mode" Combination?
|
||||
|
||||
PostgreSQL is not actually a database. It is a Relational Database Management System (RDMS). Within it, you can spawn PostgreSQL databases. In Supabase, it is a common pattern to just use the default database called postgres, but you could create more:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE postgres;
|
||||
CREATE DATABASE another_database;
|
||||
```
|
||||
|
||||
Similarly, a database can have many database users, but most people just rely on the default user "postgres".
|
||||
|
||||
```sql
|
||||
CREATE USER postgres WITH PASSWORD 'super-secret-password;
|
||||
CREATE USER some_new_user WITH PASSWORD 'password';
|
||||
```
|
||||
|
||||
The modes are transaction (port 6543) and session (port 5432) mode.
|
||||
|
||||
The "user+database+mode" combinations are formed from the above variables and are used within the connection string:
|
||||
|
||||
```
|
||||
postgres://[USER].shfmmplnqscentnakbkl:[password]@aws-0-ca-central-1.pooler.supabase.com:[MODE]/[DATABASE]
|
||||
```
|
||||
|
||||
When a distinct combination connects to your database, a new direct connection pool will be created. That means if you have two combinations connecting and the "Pool Size" is set to 120, each combination will have permission to form 120 connections. This can become problematic if collectively they exhaust all available direct connections.
|
||||
|
||||
### **Does Supavisor Immediately Establish the Max Pool Size?**
|
||||
|
||||
No, it doesn't. Let's break it down:
|
||||
|
||||
- In transaction mode, the pooler will only add connections if there are not enough connections to service all pending queries simultaneously. If 10 clients connect, but a single direct connection can comfortably accommodate them all, the pooler will not create more.
|
||||
- If necessary, it can create as many connections to prevent queries from pending up to the limit specified by the "Pool Size".
|
||||
- In session mode, it will immediately create a new a direct connection for a new client unless the "Pool Size" is reached
|
||||
- In transaction mode, once a direct connection is established, the pooler will keep it available for reuse for another client. However, if the connection remains unused for 5 minutes, the pooler will close it to free up database resources. In session mode, the connection will be immediately closed.
|
||||
- If a client is connected to the pooler, then at least 1 hot connection will be sustained, even if no client needs it.
|
||||
|
||||
### **Where Can I Change My Pool Size?**
|
||||
|
||||
In the [Dashboard's Database Settings](https://supabase.com/dashboard/project/_/settings/database), you can configure Supavisor's "Pool Size":
|
||||
|
||||
<img
|
||||
width="673"
|
||||
alt="Screenshot 2024-02-25 at 10 06 25 PM"
|
||||
src="https://github.com/supabase/supabase/assets/91111415/ce9e9d28-67c2-4dd2-ac0a-0a0150e63b4f"
|
||||
/>
|
||||
|
||||
You can also change the pool size for PostgREST's (DB API) internal pooler at the bottom of the [application settings](https://supabase.com/dashboard/project/_/settings/api).
|
||||
|
||||
### Do all services on Supabase use Supavisor?
|
||||
|
||||
Supabase Storage uses Supavisor internally. The other servers that communicate with Postgres (PostgREST, Realtime, and Auth) all rely on internal application poolers.
|
||||
|
||||
Supavisor is primarily intended for users who do not want to rely on the Supase Client libraries and instead prefer to work with external ORMs, such as Prisma, Drizzle, and Psycopg.
|
||||
|
||||
### **Should I Change Supavisor's Pool Size?**
|
||||
|
||||
In an ideal scenario, PostgreSQL would support an unlimited number of direct connections, but there's a limit to how many it can handle. If Supavisor uses most of the available connections, you risk depriving other servers, such as Auth, from accessing your database. Still, as much as possible, you want to give your pooler freedom to grow its pool as needed to service demand.
|
||||
|
||||
It's important to note that the Storage server also uses Supavisor as a unique "user+db+mode" combination, so the pool size you set for your general application will apply to it, too.
|
||||
|
||||
As a rule of thumb, if you're using the DB REST API or multiple app-based "user+db+mode" combinations, try to keep the pooler's usage under 40% of available connections. Otherwise, you can cautiously increase usage to around 80%. These percentages are flexible and depend on your application's usage and setup. Monitor connection usage to determine the optimal allocation without depriving other servers of necessary connections.
|
||||
|
||||
### **How can I Monitor Connections?**
|
||||
|
||||
> EDIT: a more in-depth [troubleshooting guide](https://github.com/orgs/supabase/discussions/27141) for connection monitoring was published
|
||||
|
||||
Connection usage can be monitored with a Supabase Grafana Dashboard. It provides realtime visibility of over 200 database metrics, such as graphs of CPU, EBS, and active direct/pooler connections. It can be extremely useful for monitoring and debugging instances.
|
||||
|
||||
You can check our [GitHub repo](https://github.com/supabase/supabase-grafana) for setup instructions for local deployments or free cloud deployments on [Fly.io](http://fly.io/). I recommend referring to our concise [documentation](https://supabase.com/docs/guides/platform/metrics) to learn more about the metrics endpoint.
|
||||
|
||||
### **Can Supavisor really Support a Million Connections?**
|
||||
|
||||
It depends.
|
||||
|
||||
In the article ["Supavisor: Scaling Postgres to 1 Million Connections"](https://supabase.com/blog/supavisor-1-million) we gave Supavisor the capacity to connect to a million clients simultaneously. The pooler triaged the clients' queries to 400 database connections.
|
||||
|
||||
What is important is that the database processing these queries had 64vCPUs and 256GB of memory. It could process the queries fast enough to ensure that there was never a noticeable bottleneck. The clients never waited long enough to timeout. If the clients were asking to run inefficient queries, like the one below, a severe backlog of pending client queries would have formed:
|
||||
|
||||
```sql
|
||||
-- do nothing for 60 seconds
|
||||
select pg_sleep(60);
|
||||
```
|
||||
|
||||
A backlog could also happen if there are not enough direct connections available. In our setup, 400 connections were enough to handle a million clients, ensuring a smooth flow of requests. But if we had only 1 direct connection, the queue would've moved too slowly and clients would expire their requests.
|
||||
|
||||
Scaling to this level only works when the pooler is operating in transaction mode. In Session mode, hypothetically, the 400 clients that first accessed the direct connections could keep them, even if they are no longer executing queries. The pending 999,600 clients waiting for a turn would then be starved of direct connections.
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
title = "Using SQLAlchemy with Supabase"
|
||||
github_url = "https://github.com/orgs/supabase/discussions/27071"
|
||||
date_created = "2024-06-06T16:27:43+00:00"
|
||||
topics = ["database", "supavisor", "self-hosting", "functions"]
|
||||
keywords = ["sqlalchemy", "ipv6", "pool", "database", "connection"]
|
||||
---
|
||||
|
||||
## Deploying to auto-scaling servers:
|
||||
|
||||
If you are deploying to:
|
||||
|
||||
- edge functions
|
||||
- serverless functions
|
||||
- horizontally auto-scaling deployments
|
||||
|
||||
It is recommended that you connect with the pooler in transaction mode (port 6543), which can be found in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database):
|
||||
|
||||
```sh
|
||||
# Example transaction mode string:
|
||||
postgres://[db-user].[project-ref]:[db-password]@aws-0-[aws-region].pooler.supabase.com:6543
|
||||
```
|
||||
|
||||
When using transaction mode, you should use the[ NullPool setting:](https://docs.sqlalchemy.org/en/20/core/pooling.html#switching-pool-implementations)
|
||||
|
||||
```py
|
||||
from sqlalchemy.pool import NullPool
|
||||
|
||||
con = sqlalchemy.create_engine(url, client_encoding='utf8', poolclass=NullPool)
|
||||
```
|
||||
|
||||
When relying on Supavisor, it's important to pick an adequate pool size. This guide can walk you through the process:
|
||||
|
||||
- https://github.com/orgs/supabase/discussions/21566
|
||||
|
||||
## Deploying to stationary servers
|
||||
|
||||
For stationary servers, such as VMs and long-running containers, it is recommended to use your direct connection string, which can be found in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database)
|
||||
|
||||
```
|
||||
# Example DB string:
|
||||
postgresql://postgres:[PASSWORD]@db.[PROJECT REF].supabase.co:5432/postgres
|
||||
```
|
||||
|
||||
The connection maps to an IPv6 address, and cannot operate in an IPv4 environment.
|
||||
|
||||
### Checking IPv6 Support:
|
||||
|
||||
The majority of services are IPv6 compatible. However, there are a few prominent services that only accept IPv4 connections:
|
||||
|
||||
- [Retool](https://retool.com/)
|
||||
- [Vercel](https://vercel.com/)
|
||||
- [GitHub Actions](https://docs.github.com/en/actions)
|
||||
- [Render](https://render.com/)
|
||||
|
||||
If you're still unsure if your network supports IPv6, you can run this cURL command on your deployment server:
|
||||
|
||||
```sh
|
||||
curl -6 https://ifconfig.co/ip
|
||||
```
|
||||
|
||||
If the command returns an IPv6 address, the network is IPv6 compatible.
|
||||
|
||||
If your deployment environment is not IPv6 compatible, then consider:
|
||||
|
||||
- Using the Supavisor pooler in session (port 5432)
|
||||
- Enabling the [IPv4 Add-On](https://supabase.com/dashboard/project/_/settings/addons) if you're on a pro or above plan
|
||||
|
||||
### Choosing an internal pool size
|
||||
|
||||
**Key Pool Settings:**
|
||||
|
||||
- pool_size: This sets the maximum number of permanent connections in the pool. SQLAlchemy will create connections as needed up to this limit.
|
||||
max_overflow: Allows creating additional connections beyond pool_size for temporary bursts in demand. These temporary connections close after use.
|
||||
|
||||
```python
|
||||
# Example configurations
|
||||
engine = create_engine(
|
||||
"postgresql+psycopg2://me@localhost/mydb", pool_size=20, max_overflow=15
|
||||
)
|
||||
```
|
||||
|
||||
As a rule of thumb, if you're using the Supabase Database REST Client, try to limit the connections used by your deployment to 40% of available connections. Otherwise, you can cautiously increase usage to around 80%. These percentages are flexible and depend on your application's usage and setup. Monitor connection usage to determine the optimal allocation without depriving other servers of necessary connections.
|
||||
|
||||
## How to monitor live connections
|
||||
|
||||
Connection usage can be monitored with a Supabase Grafana Dashboard. It provides realtime visibility of over 200 database metrics, such as graphs of CPU, EBS, and active direct/pooler connections. It can be extremely useful for monitoring and debugging instances.
|
||||
|
||||
You can check our [GitHub repo](https://github.com/supabase/supabase-grafana) for setup instructions for local deployments or free cloud deployments on [Fly.io](http://fly.io/). For a complete explainer on connection monitoring, you can check out this [guide](https://github.com/orgs/supabase/discussions/27141)
|
||||
Reference in new issue
Block a user