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 }) =>