mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 19:35:06 +03:00
* feat: setup chart area and tabs This sets up the area where we can expect the insights chart as well as the tabs mechanism. * feat: parse pg_stat_monitor logs as json * feat: create query perf chart utils and move transfrom function Created a utils file for our QueryPerformanceChart component. This moves the logs to JSON transform function there. * feat: add timerange to chart * feat: add date selector to query perf overview This adds the selector to the top right of the page allowing the user to switch between last hour, 3 hours and 24 hours * feat: modify chart component to accomodate hiding bits * feat: add metrics to each tab * chore: update to 60 min by default and some css * feat: centralise data parsing for logs * feat: clean up filters bar This rewires the export to give you the aggregate pg_stat_monitor data. Also removes unused buttons and filters. * feat: percentiles for query latency chart * feat: filter out non evenets from pg_stat_monitor logs * feat: utils for cache misses and hits * feat: add selected query to chart on click * feat: add click through to query panel * chore: tidy up files * chore: distinction between selected and open panel * feat: move query performance fully into reports area * fix: preserve query params on reports link * fix: remove right icon syntax in report menu * chore: remove cache misses from cache chart * refactor: backwards compatibility for statements if right db version isnt available * chore: delete randomly generated empty file * chore: tidy up unused imports and vars * chore: remove console logs * chore: remove isMounted from query perf * fix: cmd k query perf path * feat: simplify query latency only p50 and p95 This seems to give us a more accurate reading as we can calculate these two * fix: cache hit rate not showing inside query details * chore: chart bg colour adjust So it contrasts a little better on light mode. * feat: show selected query on other verticals * feat: bring back symlink in advisors
187 lines
6.5 KiB
TypeScript
187 lines
6.5 KiB
TypeScript
import { LoadingLine, cn } from 'ui'
|
|
import { useState, useEffect, useMemo } from 'react'
|
|
|
|
import { Button } from 'ui'
|
|
import { X, RefreshCw, RotateCcw } from 'lucide-react'
|
|
import { Markdown } from '../../Markdown'
|
|
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
|
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
|
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
|
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
|
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
|
import { DOCS_URL, IS_PLATFORM } from 'lib/constants'
|
|
import { executeSql } from 'data/sql/execute-sql-query'
|
|
import { toast } from 'sonner'
|
|
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
|
import { formatDatabaseID } from 'data/read-replicas/replicas.utils'
|
|
import { PresetHookResult } from 'components/interfaces/Reports/Reports.utils'
|
|
import { DbQueryHook } from 'hooks/analytics/useDbQuery'
|
|
import { QueryPerformanceMetrics } from '../QueryPerformanceMetrics'
|
|
import { QueryPerformanceFilterBar } from '../QueryPerformanceFilterBar'
|
|
import { QueryPerformanceGrid } from '../QueryPerformanceGrid'
|
|
import { transformStatementDataToRows } from './WithStatements.utils'
|
|
import { DownloadResultsButton } from 'components/ui/DownloadResultsButton'
|
|
|
|
interface WithStatementsProps {
|
|
queryHitRate: PresetHookResult
|
|
queryPerformanceQuery: DbQueryHook<any>
|
|
queryMetrics: PresetHookResult
|
|
}
|
|
|
|
export const WithStatements = ({
|
|
queryHitRate,
|
|
queryPerformanceQuery,
|
|
queryMetrics,
|
|
}: WithStatementsProps) => {
|
|
const { ref } = useParams()
|
|
const { data: project } = useSelectedProjectQuery()
|
|
const state = useDatabaseSelectorStateSnapshot()
|
|
const { data, isLoading, isRefetching } = queryPerformanceQuery
|
|
const isPrimaryDatabase = state.selectedDatabaseId === ref
|
|
const formattedDatabaseId = formatDatabaseID(state.selectedDatabaseId ?? '')
|
|
|
|
const [showResetgPgStatStatements, setShowResetgPgStatStatements] = useState(false)
|
|
|
|
const [showBottomSection, setShowBottomSection] = useLocalStorageQuery(
|
|
LOCAL_STORAGE_KEYS.QUERY_PERF_SHOW_BOTTOM_SECTION,
|
|
true
|
|
)
|
|
|
|
const handleRefresh = () => {
|
|
queryPerformanceQuery.runQuery()
|
|
queryHitRate.runQuery()
|
|
queryMetrics.runQuery()
|
|
}
|
|
|
|
const processedData = useMemo(() => {
|
|
return transformStatementDataToRows(data || [])
|
|
}, [data])
|
|
|
|
const { data: databases } = useReadReplicasQuery({ projectRef: ref })
|
|
|
|
useEffect(() => {
|
|
state.setSelectedDatabaseId(ref)
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [ref])
|
|
|
|
return (
|
|
<>
|
|
<QueryPerformanceMetrics />
|
|
<QueryPerformanceFilterBar
|
|
actions={
|
|
<>
|
|
<Button
|
|
type="default"
|
|
size="tiny"
|
|
icon={<RefreshCw />}
|
|
onClick={handleRefresh}
|
|
loading={isRefetching}
|
|
>
|
|
Refresh
|
|
</Button>
|
|
<Button
|
|
type="default"
|
|
size="tiny"
|
|
icon={<RotateCcw />}
|
|
onClick={() => setShowResetgPgStatStatements(true)}
|
|
>
|
|
Reset report
|
|
</Button>
|
|
<DownloadResultsButton
|
|
results={processedData}
|
|
fileName={`Supabase Query Performance Statements (${ref})`}
|
|
align="end"
|
|
/>
|
|
</>
|
|
}
|
|
/>
|
|
<LoadingLine loading={isLoading || isRefetching} />
|
|
<QueryPerformanceGrid aggregatedData={processedData} isLoading={isLoading} />
|
|
<div
|
|
className={cn('px-6 py-6 flex gap-x-4 border-t relative', {
|
|
hidden: showBottomSection === false,
|
|
})}
|
|
>
|
|
<Button
|
|
className="absolute top-1.5 right-3 px-1.5"
|
|
type="text"
|
|
size="tiny"
|
|
onClick={() => setShowBottomSection(false)}
|
|
>
|
|
<X size="14" />
|
|
</Button>
|
|
<div className="w-[33%] flex flex-col gap-y-1 text-sm">
|
|
<p>Reset report</p>
|
|
<p className="text-xs text-foreground-light">
|
|
Consider resetting the analysis after optimizing any queries
|
|
</p>
|
|
<Button
|
|
type="default"
|
|
className="!mt-3 w-min"
|
|
onClick={() => setShowResetgPgStatStatements(true)}
|
|
>
|
|
Reset report
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="w-[33%] flex flex-col gap-y-1 text-sm">
|
|
<p>How is this report generated?</p>
|
|
<Markdown
|
|
className="text-xs"
|
|
content={`This report uses the pg_stat_statements table, and pg_stat_statements extension. [Learn more here](${DOCS_URL}/guides/platform/performance#examining-query-performance).`}
|
|
/>
|
|
</div>
|
|
|
|
<div className="w-[33%] flex flex-col gap-y-1 text-sm">
|
|
<p>Inspect your database for potential issues</p>
|
|
<Markdown
|
|
className="text-xs"
|
|
content={`The Supabase CLI comes with a range of tools to help inspect your Postgres instances for
|
|
potential issues. [Learn more here](${DOCS_URL}/guides/database/inspect).`}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<ConfirmationModal
|
|
visible={showResetgPgStatStatements}
|
|
size="medium"
|
|
variant="destructive"
|
|
title="Reset query performance analysis"
|
|
confirmLabel="Reset report"
|
|
confirmLabelLoading="Resetting report"
|
|
onCancel={() => setShowResetgPgStatStatements(false)}
|
|
onConfirm={async () => {
|
|
const connectionString = databases?.find(
|
|
(db) => db.identifier === state.selectedDatabaseId
|
|
)?.connectionString
|
|
|
|
if (IS_PLATFORM && !connectionString) {
|
|
return toast.error('Unable to run query: Connection string is missing')
|
|
}
|
|
|
|
try {
|
|
await executeSql({
|
|
projectRef: project?.ref,
|
|
connectionString,
|
|
sql: `SELECT pg_stat_statements_reset();`,
|
|
})
|
|
handleRefresh()
|
|
setShowResetgPgStatStatements(false)
|
|
} catch (error: any) {
|
|
toast.error(`Failed to reset analysis: ${error.message}`)
|
|
}
|
|
}}
|
|
>
|
|
<p className="text-foreground-light text-sm">
|
|
This will reset the pg_stat_statements table in the extensions schema on your{' '}
|
|
<span className="text-foreground">
|
|
{isPrimaryDatabase ? 'primary database' : `read replica (ID: ${formattedDatabaseId})`}
|
|
</span>
|
|
, which is used to calculate query performance. This data will repopulate immediately
|
|
after.
|
|
</p>
|
|
</ConfirmationModal>
|
|
</>
|
|
)
|
|
}
|