| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817 |
- import { literal, safeSql, type SafeSqlFragment } from '@supabase/pg-meta'
- import dayjs from 'dayjs'
- import type { DatetimeHelper } from '../Settings/Logs/Logs.types'
- import { PresetConfig, Presets, ReportFilterItem } from './Reports.types'
- import { PlanId } from '@/data/subscriptions/types'
- export const LAYOUT_COLUMN_COUNT = 2
- export interface ReportsDatetimeHelper extends DatetimeHelper {
- availableIn: PlanId[]
- }
- export enum REPORT_DATERANGE_HELPER_LABELS {
- LAST_10_MINUTES = 'Last 10 minutes',
- LAST_30_MINUTES = 'Last 30 minutes',
- LAST_60_MINUTES = 'Last 60 minutes',
- LAST_3_HOURS = 'Last 3 hours',
- LAST_24_HOURS = 'Last 24 hours',
- LAST_7_DAYS = 'Last 7 days',
- LAST_14_DAYS = 'Last 14 days',
- LAST_28_DAYS = 'Last 28 days',
- }
- export const REPORTS_DATEPICKER_HELPERS: ReportsDatetimeHelper[] = [
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_10_MINUTES,
- calcFrom: () => dayjs().subtract(10, 'minute').toISOString(),
- calcTo: () => dayjs().toISOString(),
- availableIn: ['free', 'pro', 'team', 'enterprise', 'platform'],
- },
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_30_MINUTES,
- calcFrom: () => dayjs().subtract(30, 'minute').toISOString(),
- calcTo: () => dayjs().toISOString(),
- availableIn: ['free', 'pro', 'team', 'enterprise', 'platform'],
- },
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES,
- calcFrom: () => dayjs().subtract(1, 'hour').toISOString(),
- calcTo: () => dayjs().toISOString(),
- default: true,
- availableIn: ['free', 'pro', 'team', 'enterprise', 'platform'],
- },
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_3_HOURS,
- calcFrom: () => dayjs().subtract(3, 'hour').toISOString(),
- calcTo: () => dayjs().toISOString(),
- availableIn: ['free', 'pro', 'team', 'enterprise', 'platform'],
- },
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_24_HOURS,
- calcFrom: () => dayjs().subtract(1, 'day').toISOString(),
- calcTo: () => dayjs().toISOString(),
- availableIn: ['free', 'pro', 'team', 'enterprise', 'platform'],
- },
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_7_DAYS,
- calcFrom: () => dayjs().subtract(7, 'day').toISOString(),
- calcTo: () => dayjs().toISOString(),
- availableIn: ['pro', 'team', 'enterprise'],
- },
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_14_DAYS,
- calcFrom: () => dayjs().subtract(14, 'day').toISOString(),
- calcTo: () => dayjs().toISOString(),
- availableIn: ['team', 'enterprise'],
- },
- {
- text: REPORT_DATERANGE_HELPER_LABELS.LAST_28_DAYS,
- calcFrom: () => dayjs().subtract(28, 'day').toISOString(),
- calcTo: () => dayjs().toISOString(),
- availableIn: ['team', 'enterprise'],
- },
- ]
- export const DEFAULT_QUERY_PARAMS = {
- iso_timestamp_start: REPORTS_DATEPICKER_HELPERS[0].calcFrom(),
- iso_timestamp_end: REPORTS_DATEPICKER_HELPERS[0].calcTo(),
- }
- function rewriteWhereToAnd(sql: SafeSqlFragment): SafeSqlFragment {
- return sql.replace(/^WHERE/, 'AND') as SafeSqlFragment
- }
- export const generateRegexpWhere = (filters: ReportFilterItem[], prepend = true) => {
- if (filters.length === 0) return ''
- const conditions = filters
- .map((filter) => {
- const splitKey = filter.key.split('.')
- const normalizedKey = [splitKey[splitKey.length - 2], splitKey[splitKey.length - 1]].join('.')
- const filterKey = filter.key.includes('.') ? normalizedKey : filter.key
- const hasQuotes =
- filter.value.toString().includes('"') || filter.value.toString().includes("'")
- const valueIsNumber = !isNaN(Number(filter.value))
- const valueWithQuotes = !valueIsNumber && hasQuotes ? filter.value : `'${filter.value}'`
- const lowercaseValue = !valueIsNumber && String(valueWithQuotes).toLowerCase()
- const finalValue = valueIsNumber ? filter.value : lowercaseValue
- // Handle different comparison operators
- switch (filter.compare) {
- case 'matches':
- return `REGEXP_CONTAINS(${filterKey}, ${finalValue})`
- case 'is':
- return `${filterKey} = ${finalValue}`
- case '!=':
- return `${filterKey} != ${finalValue}`
- case '>=':
- return `${filterKey} >= ${finalValue}`
- case '<=':
- return `${filterKey} <= ${finalValue}`
- case '>':
- return `${filterKey} > ${finalValue}`
- case '<':
- return `${filterKey} < ${finalValue}`
- default:
- // Fallback to exact match for unknown operators
- return `${filterKey} = ${finalValue}`
- }
- })
- .filter(Boolean) // Remove any null/undefined conditions
- .join(' AND ')
- if (conditions === '') return ''
- if (prepend) {
- return 'WHERE ' + conditions
- } else {
- return 'AND ' + conditions
- }
- }
- export const PRESET_CONFIG: Record<Presets, PresetConfig> = {
- [Presets.API]: {
- title: 'API',
- queries: {
- totalRequests: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-total-requests
- select
- cast(timestamp_trunc(t.timestamp, hour) as datetime) as timestamp,
- count(t.id) as count
- FROM edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- ${generateRegexpWhere(filters)}
- GROUP BY
- timestamp
- ORDER BY
- timestamp ASC`,
- },
- topRoutes: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-top-routes
- select
- request.path as path,
- request.method as method,
- request.search as search,
- response.status_code as status_code,
- count(t.id) as count
- from edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- ${generateRegexpWhere(filters)}
- group by
- request.path, request.method, request.search, response.status_code
- order by
- count desc
- limit 10
- `,
- },
- errorCounts: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-error-counts
- select
- cast(timestamp_trunc(t.timestamp, hour) as datetime) as timestamp,
- count(t.id) as count
- FROM edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- WHERE
- response.status_code >= 400
- ${generateRegexpWhere(filters, false)}
- GROUP BY
- timestamp
- ORDER BY
- timestamp ASC
- `,
- },
- topErrorRoutes: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-top-error-routes
- select
- request.path as path,
- request.method as method,
- request.search as search,
- response.status_code as status_code,
- count(t.id) as count
- from edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- where
- response.status_code >= 400
- ${generateRegexpWhere(filters, false)}
- group by
- request.path, request.method, request.search, response.status_code
- order by
- count desc
- limit 10
- `,
- },
- responseSpeed: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-response-speed
- select
- cast(timestamp_trunc(t.timestamp, hour) as datetime) as timestamp,
- avg(response.origin_time) as avg
- FROM
- edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- ${generateRegexpWhere(filters)}
- GROUP BY
- timestamp
- ORDER BY
- timestamp ASC
- `,
- },
- topSlowRoutes: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-top-slow-routes
- select
- request.path as path,
- request.method as method,
- request.search as search,
- response.status_code as status_code,
- count(t.id) as count,
- avg(response.origin_time) as avg
- from edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- ${generateRegexpWhere(filters)}
- group by
- request.path, request.method, request.search, response.status_code
- order by
- avg desc
- limit 10
- `,
- },
- networkTraffic: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-network-traffic
- select
- cast(timestamp_trunc(t.timestamp, hour) as datetime) as timestamp,
- coalesce(
- safe_divide(
- sum(
- cast(coalesce(headers.content_length, "0") as int64)
- ),
- 1000000
- ),
- 0
- ) as ingress_mb,
- coalesce(
- safe_divide(
- sum(
- cast(coalesce(resp_headers.content_length, "0") as int64)
- ),
- 1000000
- ),
- 0
- ) as egress_mb,
- FROM
- edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- cross join unnest(response.headers) as resp_headers
- ${generateRegexpWhere(filters)}
- GROUP BY
- timestamp
- ORDER BY
- timestamp ASC
- `,
- },
- requestsByCountry: {
- queryType: 'logs',
- sql: (filters) => `
- -- reports-api-requests-by-country
- select
- cf.country as country,
- count(t.id) as count
- from edge_logs t
- cross join unnest(metadata) as m
- cross join unnest(m.response) as response
- cross join unnest(m.request) as request
- cross join unnest(request.headers) as headers
- cross join unnest(request.cf) as cf
- where
- cf.country is not null
- ${generateRegexpWhere(filters, false)}
- group by
- cf.country
- `,
- },
- },
- },
- [Presets.AUTH]: {
- title: '',
- queries: {},
- },
- [Presets.STORAGE]: {
- title: 'Storage',
- queries: {
- cacheHitRate: {
- queryType: 'logs',
- // storage report does not perform any filtering
- sql: (filters) => `
- -- reports-storage-cache-hit-rate
- SELECT
- timestamp_trunc(timestamp, hour) as timestamp,
- countif( h.cf_cache_status in ('HIT', 'STALE', 'REVALIDATED', 'UPDATING') ) as hit_count,
- countif( h.cf_cache_status in ('MISS', 'NONE/UNKNOWN', 'EXPIRED', 'BYPASS', 'DYNAMIC') ) as miss_count
- from edge_logs f
- cross join unnest(f.metadata) as m
- cross join unnest(m.request) as r
- cross join unnest(m.response) as res
- cross join unnest(res.headers) as h
- where starts_with(r.path, '/storage/v1/object') and r.method = 'GET'
- ${generateRegexpWhere(filters, false)}
- group by timestamp
- order by timestamp desc
- `,
- },
- topCacheMisses: {
- queryType: 'logs',
- // storage report does not perform any filtering
- sql: (filters) => `
- -- reports-storage-top-cache-misses
- SELECT
- r.path as path,
- r.search as search,
- count(id) as count
- from edge_logs f
- cross join unnest(f.metadata) as m
- cross join unnest(m.request) as r
- cross join unnest(m.response) as res
- cross join unnest(res.headers) as h
- where starts_with(r.path, '/storage/v1/object')
- and r.method = 'GET'
- and h.cf_cache_status in ('MISS', 'NONE/UNKNOWN', 'EXPIRED', 'BYPASS', 'DYNAMIC')
- ${generateRegexpWhere(filters, false)}
- group by path, search
- order by count desc
- limit 12
- `,
- },
- },
- },
- [Presets.QUERY_PERFORMANCE]: {
- title: 'Query performance',
- queries: {
- mostFrequentlyInvoked: {
- queryType: 'db',
- safeSql: (
- _params,
- where,
- orderBy,
- runIndexAdvisor = false,
- _filterIndexAdvisor = false
- ) => safeSql`
- -- reports-query-performance-most-frequently-invoked
- set search_path to public, extensions;
- select
- auth.rolname,
- statements.query,
- statements.calls,
- -- -- Postgres 13, 14, 15
- statements.total_exec_time + statements.total_plan_time as total_time,
- statements.min_exec_time + statements.min_plan_time as min_time,
- statements.max_exec_time + statements.max_plan_time as max_time,
- statements.mean_exec_time + statements.mean_plan_time as mean_time,
- -- -- Postgres <= 12
- -- total_time,
- -- min_time,
- -- max_time,
- -- mean_time,
- coalesce(statements.rows::numeric / nullif(statements.calls, 0), 0) as avg_rows,
- statements.rows as rows_read,
- case
- when (statements.shared_blks_hit + statements.shared_blks_read) > 0
- then round(
- (statements.shared_blks_hit * 100.0) /
- (statements.shared_blks_hit + statements.shared_blks_read),
- 2
- )
- else 0
- end as cache_hit_rate${
- runIndexAdvisor
- ? safeSql`,
- case
- when (lower(statements.query) like 'select%' or lower(statements.query) like 'with pgrst%')
- then (
- select json_build_object(
- 'has_suggestion', array_length(index_statements, 1) > 0,
- 'startup_cost_before', startup_cost_before,
- 'startup_cost_after', startup_cost_after,
- 'total_cost_before', total_cost_before,
- 'total_cost_after', total_cost_after,
- 'index_statements', index_statements
- )
- from index_advisor(statements.query)
- )
- else null
- end as index_advisor_result`
- : safeSql``
- }
- from pg_stat_statements as statements
- inner join pg_authid as auth on statements.userid = auth.oid
- -- skip queries that were never actually executed
- WHERE statements.calls > 0 ${where ? rewriteWhereToAnd(where) : safeSql``}
- ${orderBy || safeSql`order by statements.calls desc`}
- limit 20`,
- },
- mostTimeConsuming: {
- queryType: 'db',
- safeSql: (
- _,
- where,
- orderBy,
- runIndexAdvisor = false,
- _filterIndexAdvisor = false
- ) => safeSql`
- -- reports-query-performance-most-time-consuming
- set search_path to public, extensions;
- -- compute total time once up front so we don't need a window function over all rows
- with grand_total as (
- select coalesce(nullif(sum(total_exec_time + total_plan_time), 0), 1) as v
- from pg_stat_statements where calls > 0
- )
- select
- auth.rolname,
- statements.query,
- statements.calls,
- statements.total_exec_time + statements.total_plan_time as total_time,
- statements.mean_exec_time + statements.mean_plan_time as mean_time,
- coalesce(
- ((statements.total_exec_time + statements.total_plan_time) /
- (select v from grand_total)) *
- 100,
- 0
- ) as prop_total_time${
- runIndexAdvisor
- ? safeSql`,
- case
- when (lower(statements.query) like 'select%' or lower(statements.query) like 'with pgrst%')
- then (
- select json_build_object(
- 'has_suggestion', array_length(index_statements, 1) > 0,
- 'startup_cost_before', startup_cost_before,
- 'startup_cost_after', startup_cost_after,
- 'total_cost_before', total_cost_before,
- 'total_cost_after', total_cost_after,
- 'index_statements', index_statements
- )
- from index_advisor(statements.query)
- )
- else null
- end as index_advisor_result`
- : safeSql``
- }
- from pg_stat_statements as statements
- inner join pg_authid as auth on statements.userid = auth.oid
- -- skip queries that were never actually executed
- WHERE statements.calls > 0 ${where ? rewriteWhereToAnd(where) : safeSql``}
- ${orderBy || safeSql`order by total_time desc`}
- limit 20`,
- },
- slowestExecutionTime: {
- queryType: 'db',
- safeSql: (
- _params,
- where,
- orderBy,
- runIndexAdvisor = false,
- _filterIndexAdvisor = false
- ) => safeSql`
- -- reports-query-performance-slowest-execution-time
- set search_path to public, extensions;
- select
- auth.rolname,
- statements.query,
- statements.calls,
- -- -- Postgres 13, 14, 15
- statements.total_exec_time + statements.total_plan_time as total_time,
- statements.min_exec_time + statements.min_plan_time as min_time,
- statements.max_exec_time + statements.max_plan_time as max_time,
- statements.mean_exec_time + statements.mean_plan_time as mean_time,
- -- -- Postgres <= 12
- -- total_time,
- -- min_time,
- -- max_time,
- -- mean_time,
- coalesce(statements.rows::numeric / nullif(statements.calls, 0), 0) as avg_rows${
- runIndexAdvisor
- ? safeSql`,
- case
- when (lower(statements.query) like 'select%' or lower(statements.query) like 'with pgrst%')
- then (
- select json_build_object(
- 'has_suggestion', array_length(index_statements, 1) > 0,
- 'startup_cost_before', startup_cost_before,
- 'startup_cost_after', startup_cost_after,
- 'total_cost_before', total_cost_before,
- 'total_cost_after', total_cost_after,
- 'index_statements', index_statements
- )
- from index_advisor(statements.query)
- )
- else null
- end as index_advisor_result`
- : safeSql``
- }
- from pg_stat_statements as statements
- inner join pg_authid as auth on statements.userid = auth.oid
- -- skip queries that were never actually executed
- WHERE statements.calls > 0 ${where ? rewriteWhereToAnd(where) : safeSql``}
- ${orderBy || safeSql`order by max_time desc`}
- limit 20`,
- },
- queryHitRate: {
- queryType: 'db',
- safeSql: (_params) => safeSql`-- reports-query-performance-cache-and-index-hit-rate
- select
- 'index hit rate' as name,
- (sum(idx_blks_hit)) / nullif(sum(idx_blks_hit + idx_blks_read),0) 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) as ratio
- from pg_statio_user_tables;`,
- },
- unified: {
- queryType: 'db',
- safeSql: (
- _params,
- where,
- orderBy,
- runIndexAdvisor = false,
- filterIndexAdvisor = false,
- page = 1,
- pageSize = 20
- ) => {
- const offset = (page - 1) * pageSize
- // When filtering by index suggestions we need a larger scan window since we don't
- // know how many rows will match. Cap at a reasonable upper bound to avoid running
- // index_advisor() across the entire dataset on any code path where it's active.
- const INDEX_ADVISOR_SCAN_CAP = 500
- const baseScanTarget =
- filterIndexAdvisor && runIndexAdvisor ? offset + pageSize * 10 : offset + pageSize
- const baseCteLimit = runIndexAdvisor
- ? Math.min(baseScanTarget, INDEX_ADVISOR_SCAN_CAP)
- : baseScanTarget
- const baseQuery = safeSql`
- -- reports-query-performance-unified
- set search_path to public, extensions;
- -- compute total time once up front so we don't need a window function over all rows
- with grand_total as (
- select coalesce(nullif(sum(total_exec_time + total_plan_time), 0), 1) as v
- from pg_stat_statements where calls > 0
- ),
- base as (
- select
- auth.rolname,
- statements.query,
- statements.calls,
- statements.total_exec_time + statements.total_plan_time as total_time,
- statements.min_exec_time + statements.min_plan_time as min_time,
- statements.max_exec_time + statements.max_plan_time as max_time,
- statements.mean_exec_time + statements.mean_plan_time as mean_time,
- coalesce(statements.rows::numeric / nullif(statements.calls, 0), 0) as avg_rows,
- statements.rows as rows_read,
- statements.shared_blks_hit as debug_hit,
- statements.shared_blks_read as debug_read,
- case
- when (statements.shared_blks_hit + statements.shared_blks_read) > 0
- then (statements.shared_blks_hit::numeric * 100.0) /
- (statements.shared_blks_hit + statements.shared_blks_read)
- else 0
- end as cache_hit_rate,
- coalesce(
- ((statements.total_exec_time + statements.total_plan_time) /
- (select v from grand_total)) *
- 100,
- 0
- ) as prop_total_time
- from pg_stat_statements as statements
- inner join pg_authid as auth on statements.userid = auth.oid
- -- skip queries that were never actually executed
- WHERE statements.calls > 0 ${where ? rewriteWhereToAnd(where) : safeSql``}
- ${orderBy || safeSql`order by total_time desc`}
- ${baseCteLimit !== null ? safeSql`limit ${literal(baseCteLimit)}` : safeSql``}
- ),
- query_results as (
- select
- base.*${
- runIndexAdvisor
- ? safeSql`,
- case
- when (lower(base.query) like 'select%' or lower(base.query) like 'with pgrst%')
- then (
- select json_build_object(
- 'has_suggestion', array_length(index_statements, 1) > 0,
- 'startup_cost_before', startup_cost_before,
- 'startup_cost_after', startup_cost_after,
- 'total_cost_before', total_cost_before,
- 'total_cost_after', total_cost_after,
- 'index_statements', index_statements
- )
- from index_advisor(base.query)
- )
- else null
- end as index_advisor_result`
- : safeSql``
- }
- from base
- )
- select *
- from query_results
- ${filterIndexAdvisor && runIndexAdvisor ? safeSql`where (index_advisor_result->>'has_suggestion')::boolean = true` : safeSql``}
- ${orderBy || safeSql`order by total_time desc`}
- limit ${literal(pageSize)} offset ${literal(offset)}`
- return baseQuery
- },
- },
- slowQueriesCount: {
- queryType: 'db',
- safeSql: () => safeSql`
- -- reports-query-performance-slow-queries-count
- set search_path to public, extensions;
- -- Count of slow queries (> 1 second average)
- SELECT count(*) as slow_queries_count
- -- alias needed to reference columns in WHERE
- FROM pg_stat_statements as statements
- -- skip never-executed queries; mean_exec_time > 1000ms = avg over 1 second
- WHERE statements.calls > 0 AND statements.mean_exec_time > 1000;`,
- },
- queryMetrics: {
- queryType: 'db',
- safeSql: (
- _params,
- where,
- orderBy,
- _runIndexAdvisor = false,
- _filterIndexAdvisor = false
- ) => safeSql`
- -- reports-query-performance-metrics
- set search_path to public, extensions;
- SELECT
- COALESCE(ROUND(AVG(statements.rows::numeric / NULLIF(statements.calls, 0)), 1), 0) as avg_rows_per_call,
- COUNT(*) FILTER (WHERE statements.total_exec_time + statements.total_plan_time > 1000) as slow_queries,
- COALESCE(
- ROUND(
- SUM(statements.shared_blks_hit) * 100.0 /
- NULLIF(SUM(statements.shared_blks_hit + statements.shared_blks_read), 0),
- 2
- ), 0
- ) || '%' as cache_hit_rate
- FROM pg_stat_statements as statements
- -- skip queries that were never actually executed
- WHERE statements.calls > 0 ${where ? rewriteWhereToAnd(where) : safeSql``}
- ${orderBy || safeSql``}`,
- },
- },
- },
- [Presets.DATABASE]: {
- title: 'database',
- queries: {
- largeObjects: {
- queryType: 'db',
- safeSql: (_) => safeSql`-- reports-database-large-objects
- SELECT
- SCHEMA_NAME,
- relname,
- table_size
- FROM
- (SELECT
- pg_catalog.pg_namespace.nspname AS SCHEMA_NAME,
- relname,
- pg_total_relation_size(pg_catalog.pg_class.oid) AS table_size
- FROM pg_catalog.pg_class
- JOIN pg_catalog.pg_namespace ON relnamespace = pg_catalog.pg_namespace.oid
- ) t
- WHERE SCHEMA_NAME NOT LIKE 'pg_%'
- ORDER BY table_size DESC
- LIMIT 5;`,
- },
- },
- },
- }
- export const DEPRECATED_REPORTS = [
- 'total_realtime_ingress',
- 'total_rest_options_requests',
- 'total_auth_ingress',
- 'total_auth_get_requests',
- 'total_auth_post_requests',
- 'total_auth_patch_requests',
- 'total_auth_options_requests',
- 'total_storage_options_requests',
- 'total_storage_patch_requests',
- 'total_options_requests',
- 'total_rest_ingress',
- 'total_rest_get_requests',
- 'total_rest_post_requests',
- 'total_rest_patch_requests',
- 'total_rest_delete_requests',
- 'total_storage_get_requests',
- 'total_storage_post_requests',
- 'total_storage_delete_requests',
- 'total_auth_delete_requests',
- 'total_get_requests',
- 'total_patch_requests',
- 'total_post_requests',
- 'total_ingress',
- 'total_delete_requests',
- ]
- export const EDGE_FUNCTION_REGIONS = [
- {
- key: 'ap-northeast-1',
- label: 'Tokyo',
- },
- {
- key: 'ap-northeast-2',
- label: 'Seoul',
- },
- {
- key: 'ap-south-1',
- label: 'Mumbai',
- },
- {
- key: 'ap-southeast-1',
- label: 'Singapore',
- },
- {
- key: 'ap-southeast-2',
- label: 'Sydney',
- },
- {
- key: 'ca-central-1',
- label: 'Canada Central',
- },
- {
- key: 'us-east-1',
- label: 'N. Virginia',
- },
- {
- key: 'us-west-1',
- label: 'N. California',
- },
- {
- key: 'us-west-2',
- label: 'Oregon',
- },
- {
- key: 'eu-central-1',
- label: 'Frankfurt',
- },
- {
- key: 'eu-west-1',
- label: 'Ireland',
- },
- {
- key: 'eu-west-2',
- label: 'London',
- },
- {
- key: 'eu-west-3',
- label: 'Paris',
- },
- {
- key: 'sa-east-1',
- label: 'São Paulo',
- },
- ] as const
|