mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 11:25:06 +03:00
Merge pull request #12577 from supabase/chore/formatter
use prettier-plugin-sql-cst
This commit is contained in:
31 files changed
+532
-1775
No files matched your search
@@ -51,3 +51,15 @@ jobs:
|
||||
# reporter: github-pr-review
|
||||
# level: warning
|
||||
# command: npx prettier -c 'i18n/**/*.{js,jsx,ts,tsx,css,md,json}'
|
||||
|
||||
format-sql:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Install plugin
|
||||
run: npm ci
|
||||
- name: Run prettier
|
||||
run: |-
|
||||
# Check mdx files which contain sql code blocks
|
||||
grep -lr '```sql' apps/docs/pages/**/*.mdx | xargs npx prettier -c
|
||||
+7
-1
@@ -4,4 +4,10 @@ node_modules
|
||||
package-lock.json
|
||||
docker*
|
||||
apps/**/out
|
||||
**/**.mdx
|
||||
# prettier-plugin-sql-cst only supports sqlite syntax
|
||||
**/supabase/migrations/*.sql
|
||||
apps/www/schema.sql
|
||||
examples/slack-clone/nextjs-slack-clone/full-schema.sql
|
||||
# ignore files with custom js formatting
|
||||
apps/docs/pages/guides/auth/*.mdx
|
||||
apps/docs/pages/guides/integrations/*.mdx
|
||||
+2
-1
@@ -4,5 +4,6 @@
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"endOfLine": "lf"
|
||||
"endOfLine": "lf",
|
||||
"sqlKeywordCase": "lower"
|
||||
}
|
||||
@@ -101,7 +101,6 @@
|
||||
"next-transpile-modules": "9.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"openapi-types": "^12.0.2",
|
||||
"prettier": "^2.2.1",
|
||||
"sass": "^1.55.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig": "*",
|
||||
|
||||
@@ -178,9 +178,9 @@ This creates a new migration named `supabase/migrations/<timestamp>_create_emplo
|
||||
Use the seed script in `supabase/seed.sql` (created with [`supabase init`](/docs/reference/cli/usage#supabase-init)) to add sample data to the table.
|
||||
|
||||
```sql
|
||||
-- in supabase/seed.sql
|
||||
insert into
|
||||
public.employees (name)
|
||||
-- in supabase/seed.sql
|
||||
insert into public.employees
|
||||
(name)
|
||||
values
|
||||
('Erlich Bachman'),
|
||||
('Richard Hendricks'),
|
||||
@@ -200,9 +200,9 @@ You should now see the contents of `employees` in Studio.
|
||||
Use the [`reset`](/docs/reference/cli/usage#supabase-db-reset) command to revert any changes to the local database.
|
||||
|
||||
```sql
|
||||
-- run on local database to make a change
|
||||
alter table
|
||||
employees add department text default 'Hooli';
|
||||
-- run on local database to make a change
|
||||
alter table employees
|
||||
add department text default 'Hooli';
|
||||
```
|
||||
|
||||
Run the following command to reset the local database:
|
||||
|
||||
@@ -390,7 +390,7 @@ This ensures that any `delete()` or `update()` would fail if there are no accomp
|
||||
To confirm that safeupdate is enabled for queries going through the API of your project, the following query could be run:
|
||||
|
||||
```sql
|
||||
select usename,useconfig from pg_shadow where usename = 'authenticator' ;
|
||||
select usename, useconfig from pg_shadow where usename = 'authenticator';
|
||||
```
|
||||
|
||||
The expected value for `useconfig` should be:
|
||||
|
||||
@@ -30,7 +30,10 @@ Create a test table with a text array (an array of strings):
|
||||
<TabPanel id="sql" label="SQL">
|
||||
|
||||
```sql
|
||||
CREATE TABLE arraytest (id integer NOT NULL, textarray text ARRAY);
|
||||
create table arraytest (
|
||||
id integer not null,
|
||||
textarray text array
|
||||
);
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -95,7 +98,7 @@ You should see:
|
||||
<TabPanel id="sql" label="SQL">
|
||||
|
||||
```sql
|
||||
SELECT * FROM arraytest;
|
||||
select * from arraytest;
|
||||
```
|
||||
|
||||
You should see:
|
||||
|
||||
@@ -76,6 +76,7 @@ The following table shows a subset of available columns:
|
||||
A full list of statistics is available in the [pg_stat_monitor docs](https://docs.percona.com/pg-stat-monitor/reference.html#postgresql-15).
|
||||
|
||||
## Functions
|
||||
|
||||
- [`pg_stat_monitor_reset()`](https://docs.percona.com/pg-stat-monitor/functions.html): Resets the statistics tracked by the `pg_stat_monitor` view and deletes all previous data.
|
||||
- [`pg_stat_monitor_version()`](https://docs.percona.com/pg-stat-monitor/functions.html): Displays the version of the `pg_stat_monitor` extension.
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ select cron.schedule (
|
||||
Vacuum every day at 3:00am (GMT)
|
||||
|
||||
```sql
|
||||
SELECT cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
|
||||
select cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
|
||||
```
|
||||
|
||||
### Invoke Supabase Edge Function every minute
|
||||
@@ -112,7 +112,7 @@ select
|
||||
Unschedules a job called `'nightly-vacuum'`
|
||||
|
||||
```sql
|
||||
SELECT cron.unschedule('nightly-vacuum');
|
||||
select cron.unschedule('nightly-vacuum');
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
@@ -16,7 +16,6 @@ The pg_net API is in alpha. Functions signatures may change.
|
||||
|
||||
It differs from the `http` extension in that it is asynchronous by default. This makes it useful in blocking functions (like triggers).
|
||||
|
||||
|
||||
## Enable the extension
|
||||
|
||||
<Tabs
|
||||
|
||||
@@ -8,7 +8,6 @@ export const meta = {
|
||||
|
||||
`PGroonga` is a PostgreSQL extension adding a full text search indexing method based on [Groonga](https://groonga.org). While native PostgreSQL supports full text indexing, it is limited to alphabet and digit based languages. `PGroonga` offers a wider range of character support making it viable for a superset of languages supported by PostgreSQL including Japanese, Chinese, etc.
|
||||
|
||||
|
||||
## Enable the extension
|
||||
|
||||
<Tabs
|
||||
|
||||
@@ -60,13 +60,12 @@ To disable an extension, call `drop extension`.
|
||||
### Create a table to store vectors
|
||||
|
||||
```sql
|
||||
create table
|
||||
posts (
|
||||
id serial primary key,
|
||||
title text not null,
|
||||
body text not null,
|
||||
embedding vector (1536)
|
||||
);
|
||||
create table posts (
|
||||
id serial primary key,
|
||||
title text not null,
|
||||
body text not null,
|
||||
embedding vector(1536)
|
||||
);
|
||||
```
|
||||
|
||||
### Storing a vector / embedding
|
||||
|
||||
@@ -15,7 +15,6 @@ While Postgres natively runs SQL, it can also run other "procedural languages".
|
||||
|
||||
It can be used for database functions, triggers, queries and more.
|
||||
|
||||
|
||||
## Enable the extension
|
||||
|
||||
<Tabs
|
||||
|
||||
@@ -91,7 +91,7 @@ You can insert geographical data through SQL or through our API.
|
||||
|
||||
```sql
|
||||
insert into public.restaurants
|
||||
(name, location)
|
||||
(name, location)
|
||||
values
|
||||
('Supa Burger', st_point(-73.946823, 40.807416)),
|
||||
('Supa Pizza', st_point(-73.94581, 40.807475)),
|
||||
|
||||
@@ -6,7 +6,7 @@ export const meta = {
|
||||
description: '3rd party integrations for PostgreSQL ',
|
||||
}
|
||||
|
||||
[supabase/wrappers](https://supabase.github.io/wrappers/) is a PostgreSQL extension that provides integrations with external sources so you can interact with third-party data using SQL.
|
||||
[supabase/wrappers](https://supabase.github.io/wrappers/) is a PostgreSQL extension that provides integrations with external sources so you can interact with third-party data using SQL.
|
||||
|
||||
For example, the [Stripe wrapper](https://supabase.github.io/wrappers/stripe/) connects to [Stripe's API](https://stripe.com/docs/api) and exposes each endpoint as a SQL table.
|
||||
|
||||
|
||||
@@ -49,13 +49,26 @@ create table books (
|
||||
description text
|
||||
);
|
||||
|
||||
insert into books (title, author, description)
|
||||
insert into books
|
||||
(title, author, description)
|
||||
values
|
||||
('The Poky Little Puppy','Janette Sebring Lowrey','Puppy is slower than other, bigger animals.'),
|
||||
('The Tale of Peter Rabbit','Beatrix Potter','Rabbit eats some vegetables.'),
|
||||
('Tootle','Gertrude Crampton','Little toy train has big dreams.'),
|
||||
('Green Eggs and Ham','Dr. Seuss','Sam has changing food preferences and eats unusually colored food.'),
|
||||
('Harry Potter and the Goblet of Fire','J.K. Rowling','Fourth year of school starts, big drama ensues.');
|
||||
(
|
||||
'The Poky Little Puppy',
|
||||
'Janette Sebring Lowrey',
|
||||
'Puppy is slower than other, bigger animals.'
|
||||
),
|
||||
('The Tale of Peter Rabbit', 'Beatrix Potter', 'Rabbit eats some vegetables.'),
|
||||
('Tootle', 'Gertrude Crampton', 'Little toy train has big dreams.'),
|
||||
(
|
||||
'Green Eggs and Ham',
|
||||
'Dr. Seuss',
|
||||
'Sam has changing food preferences and eats unusually colored food.'
|
||||
),
|
||||
(
|
||||
'Harry Potter and the Goblet of Fire',
|
||||
'J.K. Rowling',
|
||||
'Fourth year of school starts, big drama ensues.'
|
||||
);
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -70,8 +83,7 @@ The functions we'll cover in this guide are:
|
||||
Converts your data into searchable "tokens". `to_tsvector()` stands for "to text search vector". For example:
|
||||
|
||||
```sql
|
||||
select to_tsvector('green eggs and ham')
|
||||
|
||||
select to_tsvector('green eggs and ham');
|
||||
-- Returns 'egg':2 'green':1 'ham':4
|
||||
```
|
||||
|
||||
|
||||
@@ -138,7 +138,8 @@ create table planets (
|
||||
name text
|
||||
);
|
||||
|
||||
insert into planets (id, name)
|
||||
insert into planets
|
||||
(id, name)
|
||||
values
|
||||
(1, 'Tattoine'),
|
||||
(2, 'Alderaan'),
|
||||
@@ -150,7 +151,8 @@ create table people (
|
||||
planet_id bigint references planets
|
||||
);
|
||||
|
||||
insert into people (id, name, planet_id)
|
||||
insert into people
|
||||
(id, name, planet_id)
|
||||
values
|
||||
(1, 'Anakin Skywalker', 1),
|
||||
(2, 'Luke Skywalker', 1),
|
||||
|
||||
@@ -221,12 +221,11 @@ Select the title, description, price, and age range for each book.
|
||||
```sql
|
||||
select
|
||||
title,
|
||||
metadata -> 'description' AS description,
|
||||
metadata -> 'description' as description,
|
||||
metadata -> 'price' as price,
|
||||
metadata -> 'ages' -> 0 as low_age,
|
||||
metadata -> 'ages' -> 1 as high_age
|
||||
from
|
||||
books;
|
||||
from books;
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
|
||||
@@ -12,7 +12,7 @@ Run the following query using the [SQL Editor](https://app.supabase.com/project/
|
||||
|
||||
```sql
|
||||
select
|
||||
version ();
|
||||
version();
|
||||
```
|
||||
|
||||
Which should return something like:
|
||||
|
||||
@@ -11,10 +11,11 @@ export const meta = {
|
||||
Select a set of columns from a single table with where, order by, and limit clauses.
|
||||
|
||||
```sql
|
||||
select first_name, last_name, team_id, age from players
|
||||
select first_name, last_name, team_id, age
|
||||
from players
|
||||
where age between 20 and 24 and team_id <> 'STL'
|
||||
order by last_name, first_name desc
|
||||
limit 20
|
||||
limit 20;
|
||||
```
|
||||
|
||||
```js
|
||||
@@ -32,8 +33,9 @@ const { data, error } = await supabase
|
||||
Select all columns from a single table with a complex where clause: OR AND OR
|
||||
|
||||
```sql
|
||||
select * from players
|
||||
where ((team_id = 'CHN' or team_id is null) and (age > 35 or age is null))
|
||||
select *
|
||||
from players
|
||||
where ((team_id = 'CHN' or team_id is null) and (age > 35 or age is null));
|
||||
```
|
||||
|
||||
```js
|
||||
@@ -48,8 +50,9 @@ const { data, error } = await supabase
|
||||
Select all columns from a single table with a complex where clause: AND OR AND
|
||||
|
||||
```sql
|
||||
select * from players
|
||||
where ((team_id = 'CHN' and age > 35) or (team_id <> 'CHN' and age is not null))
|
||||
select *
|
||||
from players
|
||||
where ((team_id = 'CHN' and age > 35) or (team_id <> 'CHN' and age is not null));
|
||||
```
|
||||
|
||||
```js
|
||||
@@ -62,8 +65,9 @@ const { data, error } = await supabase
|
||||
Get a count of rows, but don't return any data.
|
||||
|
||||
```sql
|
||||
select count(*) from players
|
||||
where team_id = 'NYM'
|
||||
select count(*)
|
||||
from players
|
||||
where team_id = 'NYM';
|
||||
```
|
||||
|
||||
```js
|
||||
|
||||
@@ -189,8 +189,14 @@ Use the "Bulk Loading" instructions if you are loading large data sets.
|
||||
insert into movies
|
||||
(name, description)
|
||||
values
|
||||
('The Empire Strikes Back', 'After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda.'),
|
||||
('Return of the Jedi', 'After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star.');
|
||||
(
|
||||
'The Empire Strikes Back',
|
||||
'After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda.'
|
||||
),
|
||||
(
|
||||
'Return of the Jedi',
|
||||
'After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star.'
|
||||
);
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -425,14 +431,15 @@ As a query becomes complex it becomes a hassle to call it. Especially when we ru
|
||||
|
||||
```sql
|
||||
select
|
||||
students.name,
|
||||
students.type,
|
||||
courses.title,
|
||||
courses.code,
|
||||
grades.result
|
||||
from grades
|
||||
left join students on grades.student_id = students.id
|
||||
left join courses on grades.course_id = courses.id;
|
||||
students.name,
|
||||
students.type,
|
||||
courses.title,
|
||||
courses.code,
|
||||
grades.result
|
||||
from
|
||||
grades
|
||||
left join students on grades.student_id = students.id
|
||||
left join courses on grades.course_id = courses.id;
|
||||
```
|
||||
|
||||
We can run this instead:
|
||||
@@ -449,14 +456,15 @@ Views ensure that the likelihood of mistakes decreases when repeatedly executing
|
||||
|
||||
```sql
|
||||
select
|
||||
students.name,
|
||||
students.type,
|
||||
courses.title,
|
||||
courses.code,
|
||||
grades.result
|
||||
from grades
|
||||
left join students on grades.student_id = students.id
|
||||
left join courses on grades.course_id = courses.id
|
||||
students.name,
|
||||
students.type,
|
||||
courses.title,
|
||||
courses.code,
|
||||
grades.result
|
||||
from
|
||||
grades
|
||||
left join students on grades.student_id = students.id
|
||||
left join courses on grades.course_id = courses.id
|
||||
where courses.code != 'PG101';
|
||||
```
|
||||
|
||||
@@ -478,13 +486,14 @@ Using our example above, a materialized view can be created like this:
|
||||
|
||||
```sql
|
||||
create materialized view transcripts as
|
||||
select
|
||||
students.name,
|
||||
students.type,
|
||||
courses.title,
|
||||
courses.code,
|
||||
grades.result
|
||||
from grades
|
||||
select
|
||||
students.name,
|
||||
students.type,
|
||||
courses.title,
|
||||
courses.code,
|
||||
grades.result
|
||||
from
|
||||
grades
|
||||
left join students on grades.student_id = students.id
|
||||
left join courses on grades.course_id = courses.id;
|
||||
```
|
||||
|
||||
@@ -19,9 +19,8 @@ This SQL query will show the current size of your Postgres database:
|
||||
|
||||
```sql
|
||||
select
|
||||
sum(pg_database_size (pg_database.datname)) / (1024 * 1024) as db_size_mb
|
||||
from
|
||||
pg_database;
|
||||
sum(pg_database_size(pg_database.datname)) / (1024 * 1024) as db_size_mb
|
||||
from pg_database;
|
||||
```
|
||||
|
||||
This value is reported in the [database settings page](https://app.supabase.com/project/_/settings/database).
|
||||
|
||||
@@ -168,7 +168,7 @@ Each log event stores metadata an array of objects with multiple levels, and can
|
||||
For example, to query the edge logs without any joins:
|
||||
|
||||
```sql
|
||||
select timestamp, metadata from edge_logs t
|
||||
select timestamp, metadata from edge_logs as t;
|
||||
```
|
||||
|
||||
The resulting `metadata` key is rendered as an array of objects in the Logs Explorer. In the following diagram, each box represents a nested array of objects:
|
||||
@@ -183,10 +183,11 @@ To query for a nested value, add a join for each array level:
|
||||
|
||||
```sql
|
||||
select timestamp, request.method, header.cf_ipcountry
|
||||
from edge_logs t
|
||||
cross join unnest(t.metadata) as metadata
|
||||
cross join unnest(metadata.request) as request
|
||||
cross join unnest(request.headers) as header
|
||||
from
|
||||
edge_logs as t
|
||||
cross join unnest(t.metadata) as metadata
|
||||
cross join unnest(metadata.request) as request
|
||||
cross join unnest(request.headers) as header;
|
||||
```
|
||||
|
||||
This surfaces the following columns available for selection:
|
||||
@@ -217,17 +218,19 @@ Instead, select only the values required.
|
||||
-- ❌ Avoid doing this
|
||||
select
|
||||
datetime(timestamp),
|
||||
m as metadata -- <- metadata contains many nested keys
|
||||
from edge_logs t
|
||||
cross join unnest(t.metadata) as m;
|
||||
m as metadata -- <- metadata contains many nested keys
|
||||
from
|
||||
edge_logs as t
|
||||
cross join unnest(t.metadata) as m;
|
||||
|
||||
-- ✅ Do this
|
||||
select
|
||||
datetime(timestamp),
|
||||
r.method -- <- select only the required values
|
||||
from edge_logs t
|
||||
cross join unnest(t.metadata) as m
|
||||
cross join unnest(m.request) as r
|
||||
datetime(timestamp),
|
||||
r.method -- <- select only the required values
|
||||
from
|
||||
edge_logs as t
|
||||
cross join unnest(t.metadata) as m
|
||||
cross join unnest(m.request) as r;
|
||||
```
|
||||
|
||||
### Examples and Templates
|
||||
@@ -238,11 +241,12 @@ For example, you can enter the following query in the SQL Editor to retrieve eac
|
||||
|
||||
```sql
|
||||
select datetime(timestamp), h.x_real_ip
|
||||
from edge_logs
|
||||
from
|
||||
edge_logs
|
||||
cross join unnest(metadata) as m
|
||||
cross join unnest(m.request) AS r
|
||||
cross join unnest(r.headers) AS h
|
||||
where h.x_real_ip is not null and r.method = "GET"
|
||||
cross join unnest(m.request) as r
|
||||
cross join unnest(r.headers) as h
|
||||
where h.x_real_ip is not null and r.method = "GET";
|
||||
```
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
@@ -14,13 +14,13 @@ Unoptimized queries are a major cause of poor database performance. The techniqu
|
||||
|
||||
Database performance is a large topic and many factors can contribute. Some of the most common causes of poor performance include:
|
||||
|
||||
* An inefficiently designed schema
|
||||
* Inefficiently designed queries
|
||||
* A lack of indexes causing slower than required queries over large tables
|
||||
* Unused indexes causing slow `INSERT`, `UPDATE` and `DELETE` operations
|
||||
* Not enough compute resources, such as memory, causing your database to go to disk for results too often
|
||||
* Lock contention from multiple queries operating on highly utilized tables
|
||||
* Large amount of bloat on your tables causing poor query planning
|
||||
- An inefficiently designed schema
|
||||
- Inefficiently designed queries
|
||||
- A lack of indexes causing slower than required queries over large tables
|
||||
- Unused indexes causing slow `INSERT`, `UPDATE` and `DELETE` operations
|
||||
- Not enough compute resources, such as memory, causing your database to go to disk for results too often
|
||||
- Lock contention from multiple queries operating on highly utilized tables
|
||||
- Large amount of bloat on your tables causing poor query planning
|
||||
|
||||
Thankfully there are solutions to all these issues, which we will cover in the following sections.
|
||||
|
||||
@@ -48,13 +48,11 @@ select
|
||||
-- max_time,
|
||||
-- mean_time,
|
||||
statements.rows / statements.calls as avg_rows
|
||||
|
||||
from pg_stat_statements as statements
|
||||
from
|
||||
pg_stat_statements as statements
|
||||
inner join pg_authid as auth on statements.userid = auth.oid
|
||||
order by
|
||||
statements.calls desc
|
||||
limit
|
||||
100;
|
||||
order by statements.calls desc
|
||||
limit 100;
|
||||
```
|
||||
|
||||
This query shows:
|
||||
@@ -63,7 +61,7 @@ This query shows:
|
||||
- the role that ran the query
|
||||
- the number of times it has been called
|
||||
- the average number of rows returned
|
||||
- the cumulative total time the query has spent running
|
||||
- the cumulative total time the query has spent running
|
||||
- the min, max and mean query times.
|
||||
|
||||
This provides useful information about the queries you run most frequently. Queries that have high `max_time` or `mean_time` times and are being called often can be good candidates for optimization.
|
||||
@@ -86,12 +84,11 @@ select
|
||||
-- max_time,
|
||||
-- mean_time,
|
||||
statements.rows / statements.calls as avg_rows
|
||||
from pg_stat_statements as statements
|
||||
inner join pg_authid as auth on statements.userid = auth.oid
|
||||
order by
|
||||
max_time desc
|
||||
limit
|
||||
100;
|
||||
from
|
||||
pg_stat_statements as statements
|
||||
inner join pg_authid as auth on statements.userid = auth.oid
|
||||
order by max_time desc
|
||||
limit 100;
|
||||
```
|
||||
|
||||
This query will show you statistics about queries ordered by the maximum execution time. It is similar to the query above ordered by calls, but this one highlights outliers that may have high executions times. Queries which have high or mean execution times are good candidates for optimisation.
|
||||
@@ -104,13 +101,19 @@ select
|
||||
statements.query,
|
||||
statements.calls,
|
||||
statements.total_exec_time + statements.total_plan_time as total_time,
|
||||
to_char(((statements.total_exec_time + statements.total_plan_time)/sum(statements.total_exec_time + statements.total_plan_time) over()) * 100, 'FM90D0') || '%' as prop_total_time
|
||||
from pg_stat_statements as statements
|
||||
to_char(
|
||||
(
|
||||
(statements.total_exec_time + statements.total_plan_time) / sum(
|
||||
statements.total_exec_time + statements.total_plan_time
|
||||
) over ()
|
||||
) * 100,
|
||||
'FM90D0'
|
||||
) || '%' as prop_total_time
|
||||
from
|
||||
pg_stat_statements as statements
|
||||
inner join pg_authid as auth on statements.userid = auth.oid
|
||||
order by
|
||||
total_time desc
|
||||
limit
|
||||
100;
|
||||
order by total_time desc
|
||||
limit 100;
|
||||
```
|
||||
|
||||
This query will show you statistics about queries ordered by the cumulative total execution time. It shows the total time the query has spent running as well as the proportion of total execution time the query has taken up.
|
||||
@@ -128,12 +131,12 @@ You can view your cache and index hit rate by executing the following query:
|
||||
```sql
|
||||
select
|
||||
'index hit rate' as name,
|
||||
(sum(idx_blks_hit)) / nullif(sum(idx_blks_hit + idx_blks_read),0) * 100 as ratio
|
||||
(sum(idx_blks_hit)) / nullif(sum(idx_blks_hit + idx_blks_read), 0) * 100 as ratio
|
||||
from pg_statio_user_indexes
|
||||
union all
|
||||
select
|
||||
'table hit rate' as name,
|
||||
sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read),0) * 100 as ratio
|
||||
sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read), 0) * 100 as ratio
|
||||
from pg_statio_user_tables;
|
||||
```
|
||||
|
||||
@@ -141,7 +144,6 @@ This shows the ratio of data blocks fetched from the Postgres [shared_buffers](h
|
||||
|
||||
If either of your index or table hit rate are < 99% then this can indicate your compute plan is too small for your current workload and you would benefit from more memory. [Upgrading your compute](https://supabase.com/docs/guides/platform/compute-add-ons) is easy and can be done from your [project dashboard](https://app.supabase.com/project/_/settings/billing/subscription).
|
||||
|
||||
|
||||
### Optimizing poor performing queries
|
||||
|
||||
Postgres has built in tooling to help you optimize poorly performing queries. You can use the [query plan analyzer](https://www.postgresql.org/docs/current/sql-explain.html) on any expensive queries that you have identified:
|
||||
|
||||
@@ -41,8 +41,10 @@ client libraries. Here we create a bucket called "avatars":
|
||||
```sql
|
||||
-- Use Postgres to create a bucket.
|
||||
|
||||
insert into storage.buckets (id, name)
|
||||
values ('avatars', 'avatars');
|
||||
insert into storage.buckets
|
||||
(id, name)
|
||||
values
|
||||
('avatars', 'avatars');
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
|
||||
@@ -158,8 +158,8 @@ Supabase comes with two built-in helper functions: `auth.uid()` and `auth.jwt()`
|
||||
To create your own functions, navigate to the SQL editor and create a a new query.
|
||||
|
||||
```sql
|
||||
create or replace function user_agent()
|
||||
returns text
|
||||
create or replace function user_agent()
|
||||
returns text
|
||||
language sql
|
||||
as $$
|
||||
select nullif(current_setting('request.headers', true)::json->>'user-agent', '')::text;
|
||||
|
||||
@@ -45,12 +45,16 @@ Let's say we create a leaderboard table. We want people on our website to be abl
|
||||
|
||||
```sql
|
||||
create table leaderboard (
|
||||
name text,
|
||||
score int
|
||||
name text,
|
||||
score int
|
||||
);
|
||||
|
||||
insert into leaderboard(name, score)
|
||||
values ('Paul', 100), ('Leto', 50), ('Chani', 200);
|
||||
insert into leaderboard
|
||||
(name, score)
|
||||
values
|
||||
('Paul', 100),
|
||||
('Leto', 50),
|
||||
('Chani', 200);
|
||||
```
|
||||
|
||||
Now let's set up a client to read the data, I've created a repl here to show a living example: [https://replit.com/@awalias/supabase-leaderboard-demo#index.js](https://replit.com/@awalias/supabase-leaderboard-demo#index.js). If you copy the snippet you can plug in your own Supabase URL and anon key.
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
"file-loader": "^6.2.0",
|
||||
"postcss": "^8.4.18",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"prettier": "^2.2.1",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"tsconfig": "*"
|
||||
},
|
||||
|
||||
Generated
+342
-1630
File diff suppressed because it is too large.
Load diff
+4
-13
@@ -33,10 +33,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/json-stringify-safe": "^5.0.0",
|
||||
"aws-sdk": "^2.1315.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-custom": "*",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"prettier": "^2.5.1",
|
||||
"prettier": "^2.8.4",
|
||||
"prettier-plugin-sql-cst": "^0.5.0",
|
||||
"ts-jest": "^27.0.7",
|
||||
"turbo": "^1.4.7"
|
||||
},
|
||||
@@ -55,16 +57,5 @@
|
||||
"functions",
|
||||
"database",
|
||||
"auth"
|
||||
],
|
||||
"dependencies": {
|
||||
"@code-hike/mdx": "^0.7.4",
|
||||
"@mdx-js/react": "^2.1.1",
|
||||
"aws-sdk": "^2.1315.0",
|
||||
"mdx-mermaid": "^1.3.2",
|
||||
"mermaid": "^9.2.2",
|
||||
"mini-svg-data-uri": "^1.4.4"
|
||||
},
|
||||
"overrides": {
|
||||
"pgsql-parser": "13.4.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -107,7 +107,7 @@
|
||||
"@storybook/addon-links": "^6.4.19",
|
||||
"@storybook/react": "^6.4.19",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"@supabase/postgres-meta": "^0.60.2",
|
||||
"@supabase/postgres-meta": "^0.60.7",
|
||||
"@tailwindcss/typography": "^0.5.2",
|
||||
"@testing-library/dom": "^8.19.0",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
|
||||
Reference in new issue
Block a user