From fd230d657f47aa0dffa3b844359fb7fe4e84b3d7 Mon Sep 17 00:00:00 2001 From: Copple <10214025+kiwicopple@users.noreply.github.com> Date: Mon, 13 Nov 2023 06:58:05 +0100 Subject: [PATCH] Docs: explain() (#18886) * direct copy from ChatGPT * add new menu item, clean up items * fix TOC video * fix formatting from GPT * Renaming the page - it should be more like a "job to be done" rather than "here is a specific function" * re-ordering the sections - get people using it first, then teach them the details * Adds the explain section to the docs --- .../NavigationMenu.constants.ts | 13 +- .../guides/api/rest/debugging-performance.mdx | 115 ++++++++++++++++++ .../guides/api/rest/generating-types.mdx | 12 +- spec/common-client-libs-sections.json | 8 ++ spec/supabase_js_v2.yml | 48 +------- 5 files changed, 139 insertions(+), 57 deletions(-) create mode 100644 apps/docs/pages/guides/api/rest/debugging-performance.mdx diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index eba0a013dc4..3a1e783e08c 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -791,15 +791,18 @@ export const api: NavMenuConstant = { name: 'Guides', url: '/guides/api', items: [ - { name: 'Creating API routes', url: '/guides/api/creating-routes', items: [] }, - { name: 'How API Keys work', url: '/guides/api/api-keys', items: [] }, - { name: 'Securing your API', url: '/guides/api/securing-your-api', items: [] }, + { name: 'Creating API routes', url: '/guides/api/creating-routes' }, + { name: 'How API Keys work', url: '/guides/api/api-keys' }, + { name: 'Securing your API', url: '/guides/api/securing-your-api' }, + { + name: 'Debugging performance issues', + url: '/guides/api/rest/debugging-performance', + }, { name: 'Querying joins and nested tables', url: '/guides/api/joins-and-nesting', - items: [], }, - { name: 'Using custom schemas', url: '/guides/api/using-custom-schemas', items: [] }, + { name: 'Using custom schemas', url: '/guides/api/using-custom-schemas' }, ], }, ], diff --git a/apps/docs/pages/guides/api/rest/debugging-performance.mdx b/apps/docs/pages/guides/api/rest/debugging-performance.mdx new file mode 100644 index 00000000000..84aa7786d7d --- /dev/null +++ b/apps/docs/pages/guides/api/rest/debugging-performance.mdx @@ -0,0 +1,115 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + id: 'debugging-performance', + title: 'Debugging performance issues', + description: 'Debug slow-running queries using the Postgres execution planner.', + subtitle: 'Debug slow-running queries using the Postgres execution planner.', +} + +`explain()` is a method that provides the Postgres `EXPLAIN` execution plan of a query. It is a powerful tool for debugging slow queries and understanding how Postgres will execute a given query. This feature is applicable to any query, including those made through `rpc()` or write operations. + +## Enabling `explain()` + +`explain()` is disabled by default to protect sensitive information about your database structure and operations. We recommend using `explain()` in a non-production environment. Run the following SQL to enable `explain()`: + +{/* prettier-ignore */} +```sql +-- enable explain +alter role authenticator +set pgrst.db_plan_enabled to 'true'; + +-- reload the config +notify pgrst, 'reload config'; +``` + +## Using `explain()` + +To get the execution plan of a query, you can chain the `explain()` method to a Supabase query: + +{/* prettier-ignore */} +```ts +const { data, error } = await supabase + .from('countries') + .select() + .explain() +``` + +### Example data + +To illustrate, consider the following setup of a `countries` table: + +{/* prettier-ignore */} +```sql +create table countries ( + id int8 primary key, + name text +); + +insert into countries + (id, name) +values + (1, 'Afghanistan'), + (2, 'Albania'), + (3, 'Algeria'); +``` + +### Expected response + +The response would typically look like this: + +{/* prettier-ignore */} +```markdown +Aggregate (cost=33.34..33.36 rows=1 width=112) + -> Limit (cost=0.00..18.33 rows=1000 width=40) + -> Seq Scan on countries (cost=0.00..22.00 rows=1200 width=40) +``` + +By default, the execution plan is returned in TEXT format. However, you can also retrieve it as JSON by specifying the `format` parameter. + +## Production use with pre-request protection + +If you need to enable `explain()` in a production environment, ensure you protect your database by restricting access to the `explain()` feature. You can do so by using a pre-request function that filters requests based on the IP address: + +{/* prettier-ignore */} +```sql +create or replace function filter_plan_requests() +returns void as $$ +declare + headers json := current_setting('request.headers', true)::json; + client_ip text := coalesce(headers->>'cf-connecting-ip', ''); + accept text := coalesce(headers->>'accept', ''); + your_ip text := '123.123.123.123'; -- replace this with your IP +begin + if accept like 'application/vnd.pgrst.plan%' and client_ip != your_ip then + raise insufficient_privilege using + message = 'Not allowed to use application/vnd.pgrst.plan'; + end if; +end; $$ language plpgsql; +alter role authenticator set pgrst.db_pre_request to 'filter_plan_requests'; +notify pgrst, 'reload config'; +``` + +Replace `'123.123.123.123'` with your actual IP address. + +## Disabling explain + +To disable the `explain()` method after use, execute the following SQL commands: + +{/* prettier-ignore */} +```sql +-- disable explain +alter role authenticator +set pgrst.db_plan_enabled to 'false'; + +-- if you used the above pre-request +alter role authenticator +set pgrst.db_pre_request to ''; + +-- reload the config +notify pgrst, 'reload config'; +``` + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/api/rest/generating-types.mdx b/apps/docs/pages/guides/api/rest/generating-types.mdx index 5baad562ba0..d42d66ecddb 100644 --- a/apps/docs/pages/guides/api/rest/generating-types.mdx +++ b/apps/docs/pages/guides/api/rest/generating-types.mdx @@ -4,20 +4,12 @@ export const meta = { id: 'generating-types', title: 'Generating Types', description: 'How to generate types for your API and Supabase libraries.', - video: 'https://www.youtube.com/v/7CqlTU9aOR4', + subtitle: 'How to generate types for your API and Supabase libraries.', + tocVideo: '/7CqlTU9aOR4', } Supabase APIs are generated from your database, which means that we can use database introspection to generate type-safe API definitions. -
- -
- ## Generating types using Supabase CLI The Supabase CLI is a single binary Go application that provides everything you need to setup a local development environment. diff --git a/spec/common-client-libs-sections.json b/spec/common-client-libs-sections.json index e0f062e2b24..475c0d04cae 100644 --- a/spec/common-client-libs-sections.json +++ b/spec/common-client-libs-sections.json @@ -372,6 +372,14 @@ "product": "database", "parent": "modifiers", "type": "function" + }, + { + "id": "explain", + "title": "Using explain", + "slug": "explain", + "product": "database", + "parent": "modifiers", + "type": "function" } ] } diff --git a/spec/supabase_js_v2.yml b/spec/supabase_js_v2.yml index ede65fc60e9..173269b3913 100644 --- a/spec/supabase_js_v2.yml +++ b/spec/supabase_js_v2.yml @@ -4320,6 +4320,7 @@ functions: ``` hideCodeBlock: true isSpotlight: true + - id: csv $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.csv' title: csv() @@ -4358,6 +4359,7 @@ functions: By default, the data is returned in JSON format, but can also be returned as Comma Separated Values. hideCodeBlock: true isSpotlight: true + - id: returns $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.returns' title: returns() @@ -4378,55 +4380,17 @@ functions: hideCodeBlock: true isSpotlight: true - - id: using-explain + - id: explain + $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.explain' title: Using Explain description: | - For debugging slow queries, you can get the [PostgreSQL EXPLAIN execution plan](https://www.postgresql.org/docs/current/sql-explain.html) of a query + For debugging slow queries, you can get the [Postgres `EXPLAIN` execution plan](https://www.postgresql.org/docs/current/sql-explain.html) of a query using the `explain()` method. This works on any query, even for `rpc()` or writes. Explain is not enabled by default as it can reveal sensitive information about your database. It's best to only enable this for testing environments but if you wish to enable it for production you can provide additional protection by using a `pre-request` function. - To enable it: - - ```sql - alter role authenticator set pgrst.db_plan_enabled to 'true'; - notify pgrst, 'reload config'; - ``` - - To only allow `explain()` from a fixed IP address you can do the following. Use this if you plan on enabling `explain()` on a production environment. - - ```sql - create or replace function filter_plan_requests() - returns void as $$ - declare - headers json := current_setting('request.headers', true)::json; - client_ip text := coalesce(headers->>'cf-connecting-ip', ''); - accept text := coalesce(headers->>'accept', ''); - your_ip text := '123.123.123.123'; -- replace this by your ip - begin - if accept like 'application/vnd.pgrst.plan%' and client_ip != your_ip then - raise insufficient_privilege using - message = 'Not allowed to use application/vnd.pgrst.plan'; - end if; - end; $$ language plpgsql; - - alter role authenticator set pgrst.db_pre_request to 'filter_plan_requests'; - notify pgrst, 'reload config'; - ``` - - Once you're done using `explain()`, you can disable it with: - - ```sql - alter role authenticator set pgrst.db_plan_enabled to 'false'; - -- if you used the above pre-request - alter role authenticator set pgrst.db_pre_request to ''; - - notify pgrst, 'reload config'; - ``` - - id: explain - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.explain' - title: explain() + Follow the [Performance Debugging Guide](/docs/guides/api/rest/debugging-performance) to enable the functionality on your project. examples: - id: get-execution-plan name: Get the execution plan