mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Docs update. Restructure, mostly moved lines, plus inbound anchor fixes. ## What is the current behavior? The page states the same routing decision four times and never states an answer: - Intro bullets - A matrix table - A "How to choose the right connection method?" section - A Mermaid flowchart An agent asked "I'm deploying to Vercel serverless functions, set up the database connection" has to synthesize an answer from four partial, inconsistent restatements. Context, procedure, and reference material are interleaved throughout, so background reading interrupts the action path. The page is also too long at 2,883 words, and grouping alone doesn't fix that. Explainer and reference material need their own page, and the troubleshooting group belongs in troubleshooting entries. 16 of the 19 inbound anchor links to this page are already broken on `master`, before any restructure: `#direct-connections`, `#shared-pooler`, `#connection-pooler`, `#how-connection-pooling-works`, `#quick-summary`, `#connection-pool`, and `#connecting-with-drizzle`. Groundwork for [DOCS-1312](https://linear.app/supabase/issue/DOCS-1312). The issue stays open until the paired eval is re-run. ## What is the new behavior? Group the guide into a decision, a procedure, context, reference, and troubleshooting, per CONTRIBUTING § Guides on mixed information types. Review with `git diff --color-moved=zebra`. - Lead with "Which connection method do you use?", a decision table keyed on where your code runs. Section navigation sits directly below the intro. - Collect every connection string under "Get your connection string", with the shared Connect dialog steps stated once as a procedure. - Move the endpoint, port, pool size, and connection limit material into "Connection reference". These were FAQ questions. - Split the page. The guide keeps the decision, the connection strings, and the quickstarts, at 1,180 words and three paths. A new child page, Connection pooling and limits, carries how pooling works, pool size, connection limits, and monitoring. - Move the endpoint and IP version table up beside the connection strings it explains. - Replace the troubleshooting group with two new troubleshooting entries, `tenant-or-user-not-found` and `fatal-password-authentication-failed`, plus links to the existing entries. The existing connection-refused entry is stronger than what was here: it names the IP ban and gives the unban procedure. - Cut the pool size worked example. It said a pool size of 30 is a shared ceiling across session and transaction mode, while the Supavisor FAQ and the terminology entry both say pool size is per user, database, and mode combination. That text came from `master`, so the contradiction is pre-existing. Link the FAQ as the authority rather than picking a side. - Drop the duplicate `pg_stat_ssl` query, which already exists in `connection-management.mdx` and `monitor-supavisor-postgres-connections.mdx`, both with column tables this page lacked. - Add the subsection to the navigation, which also adopts `connecting-to-postgres/serverless-drivers`. That page existed on disk and was referenced nowhere in the navigation constants. - Delete the decision flowchart. It was the fourth restatement of the decision table, and its logic was broken: `Persistent Backend` had two unconditional edges into decision nodes that each had one unlabeled output, so neither node decided anything. - Fix every broken inbound anchor, and pin stable anchors on the headings they target. This now includes six files in `apps/www` that no earlier pass in this stack checked, most of which were already broken on `master`. - Repoint the Studio Connect sheet's Drizzle link at the Drizzle guide. It pointed at a heading this page hasn't had for some time. - Serverless drivers: state the guide's intent, give the three runtimes parallel structure, and link the transaction mode prepared statements constraint. That page never mentioned the constraint that most affects serverless connections. ## Additional context PR 2 of 2. Base is #49868, rebased on its review feedback commit. Three of the 13 files are in `apps/studio`, so this runs the Studio unit tests, build, and lint ratchet. They are link string changes only. The ESLint warning count is unchanged at 1 on the touched files, so the ratchet holds. ## Manual testing 1. Open [Connect to your database](https://docs-git-docs-connecting-to-postgres-structure-supabase.vercel.app/docs/guides/database/connecting-to-postgres) on the deploy preview. 2. Check the table of contents. The top level reads: Which connection method do you use?, Get your connection string, Quickstarts, Related. The intro lists three paths. 3. Open [Reports](https://docs-git-docs-connecting-to-postgres-structure-supabase.vercel.app/docs/guides/monitoring-and-debugging/reports) and follow "Implement connection pooling" under Disk IO. It lands on the decision table. 4. Open [Serverless drivers](https://docs-git-docs-connecting-to-postgres-structure-supabase.vercel.app/docs/guides/database/connecting-to-postgres/serverless-drivers). The intro links the transaction mode prepared statements constraint. 5. Check the sidebar. Connecting to your database expands to Connection pooling and limits and Serverless drivers. 6. Open [Connection pooling and limits](https://docs-git-docs-connecting-to-postgres-structure-supabase.vercel.app/docs/guides/database/connecting-to-postgres/pooling-and-limits). Pool size states the setting and links the Supavisor FAQ, with no worked example. 7. Open [Tenant or user not found](https://docs-git-docs-connecting-to-postgres-structure-supabase.vercel.app/docs/guides/troubleshooting/tenant-or-user-not-found). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a dedicated guide covering connection pooling, limits, configuration, and monitoring. * Added troubleshooting guides for password authentication failures and shared pooler tenant or user errors. * Expanded connection guidance with method selection, endpoints, IP versions, and serverless driver configuration. * **Documentation** * Reorganized database connection documentation and navigation. * Updated related links throughout the documentation to current connection and pooling guidance. * Improved guidance for pooler modes, connection strings, and supported deployment environments. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
141 lines
5.6 KiB
Plaintext
141 lines
5.6 KiB
Plaintext
---
|
|
title: 'Managing Indexes in Postgres'
|
|
description: 'Improve query performance using various index types in Postgres'
|
|
footerHelpType: 'postgres'
|
|
tocVideo: 'bBu_V8CfWgM'
|
|
---
|
|
|
|
An index makes your Postgres queries faster. The index is like a "table of contents" for your data - a reference list which allows queries to locate a row in a given table without needing to scan the entire table (which in large tables can take a long time).
|
|
|
|
Indexes can be structured in a few different ways. The type of index chosen depends on the values you are indexing. By far the most common index type, and the default in Postgres, is the B-Tree. A B-Tree is the generalized form of a binary search tree, where nodes can have more than two children.
|
|
|
|
Even though indexes improve query performance, the Postgres query planner may not always make use of a given index when choosing which optimizations to make. Additionally indexes come with some overhead - additional writes and increased storage - so it's useful to understand how and when to use indexes, if at all.
|
|
|
|
## Create an index
|
|
|
|
Start with an example table:
|
|
|
|
```sql
|
|
create table persons (
|
|
id bigint generated by default as identity primary key,
|
|
age int,
|
|
height int,
|
|
weight int,
|
|
name text,
|
|
deceased boolean
|
|
);
|
|
```
|
|
|
|
<Admonition type="note">
|
|
|
|
All the queries in this guide can be run using the [SQL Editor](/dashboard/project/_/sql) in the Supabase Dashboard, or via `psql` if you're [connecting directly to the database](/docs/guides/database/connecting-to-postgres#direct-connection).
|
|
|
|
</Admonition>
|
|
|
|
We might want to frequently query users based on their age:
|
|
|
|
```sql
|
|
select name from persons where age = 32;
|
|
```
|
|
|
|
Without an index, Postgres will scan every row in the table to find equality matches on age.
|
|
|
|
You can verify this by doing an explain on the query:
|
|
|
|
```sql
|
|
explain select name from persons where age = 32;
|
|
```
|
|
|
|
Outputs:
|
|
|
|
```
|
|
Seq Scan on persons (cost=0.00..22.75 rows=x width=y)
|
|
Filter: (age = 32)
|
|
```
|
|
|
|
To add a basic B-Tree index you can run:
|
|
|
|
```sql
|
|
create index idx_persons_age on persons (age);
|
|
```
|
|
|
|
<Admonition type="caution">
|
|
|
|
It can take a long time to build indexes on large datasets and the default behaviour of `create index` is to lock the table from writes.
|
|
|
|
Luckily Postgres provides us with `create index concurrently` which prevents blocking writes on the table, but does take a bit longer to build.
|
|
|
|
</Admonition>
|
|
|
|
Here is a simplified diagram of the index we created (note that in practice, nodes have more than two children).
|
|
|
|
<Image
|
|
alt="B-Tree index example in Postgres"
|
|
|
|
src={{
|
|
dark: '/docs/img/database/managing-indexes/creating-indexes.png',
|
|
light: '/docs/img/database/managing-indexes/creating-indexes--light.png',
|
|
}}
|
|
width={1600}
|
|
height={1091}
|
|
/>
|
|
|
|
You can see that in any large data set, traversing the index to locate a given value can be done in much less operations (O(log n)) than compared to scanning the table one value at a time from top to bottom (O(n)).
|
|
|
|
## Partial indexes
|
|
|
|
If you are frequently querying a subset of rows then it may be more efficient to build a partial index. In our example, perhaps we only want to match on `age` where `deceased is false`. We could build a partial index:
|
|
|
|
```sql
|
|
create index idx_living_persons_age on persons (age)
|
|
where deceased is false;
|
|
```
|
|
|
|
## Ordering indexes
|
|
|
|
By default B-Tree indexes are sorted in ascending order, but sometimes you may want to provide a different ordering. Perhaps our application has a page featuring the top 10 oldest people. Here we would want to sort in descending order, and include `NULL` values last. For this we can use:
|
|
|
|
```sql
|
|
create index idx_persons_age_desc on persons (age desc nulls last);
|
|
```
|
|
|
|
## Reindexing
|
|
|
|
After a while indexes can become stale and may need rebuilding. Postgres provides a `reindex` command for this, but due to Postgres locks being placed on the index during this process, you may want to make use of the `concurrent` keyword.
|
|
|
|
```sql
|
|
reindex index concurrently idx_persons_age;
|
|
```
|
|
|
|
Alternatively you can reindex all indexes on a particular table:
|
|
|
|
```sql
|
|
reindex table concurrently persons;
|
|
```
|
|
|
|
Take note that `reindex` can be used inside a transaction, but `reindex [index/table] concurrently` cannot.
|
|
|
|
## Index Advisor
|
|
|
|
Indexes can improve query performance of your tables as they grow. The Supabase Dashboard offers an Index Advisor, which suggests potential indexes to add to your tables.
|
|
|
|
For more information on the Index Advisor and its suggestions, see the [`index_advisor` extension](/docs/guides/database/extensions/index_advisor).
|
|
|
|
To use the Dashboard Index Advisor:
|
|
|
|
1. Go to the [Query Performance](/dashboard/project/_/advisors/query-performance) page.
|
|
1. Click on a query to bring up the Details side panel.
|
|
1. Select the Indexes tab.
|
|
1. Enable Index Advisor if prompted.
|
|
|
|
### Understanding Index Advisor results
|
|
|
|
The Indexes tab shows the existing indexes used in the selected query. Note that indexes suggested in the "New Index Recommendations" section may not be used when you create them. Postgres' query planner may intentionally ignore an available index if it determines that the query will be faster without. For example, on a small table, a sequential scan might be faster than an index scan. In that case, the planner will switch to using the index as the table size grows, helping to future proof the query.
|
|
|
|
If additional indexes might improve your query, the Index Advisor shows the suggested indexes with the estimated improvement in startup and total costs:
|
|
|
|
- Startup cost is the cost to fetch the first row
|
|
- Total cost is the cost to fetch all the rows
|
|
|
|
Costs are in arbitrary units, where a single sequential page read costs 1.0 units.
|