diff --git a/app/[name]/clickhouse-queries.ts b/app/[name]/clickhouse-queries.ts index ed065441..70990a67 100644 --- a/app/[name]/clickhouse-queries.ts +++ b/app/[name]/clickhouse-queries.ts @@ -31,6 +31,14 @@ export const queries: Array = [ query_id: ColumnFormat.Action, }, relatedCharts: [ + [ + 'query-count', + { + title: 'Total Running Queries over last 12 hours (query / 5 minutes)', + interval: 'toStartOfFiveMinutes', + lastHours: 12, + }, + ], [ 'query-count-by-user', { @@ -40,14 +48,6 @@ export const queries: Array = [ showLegend: false, }, ], - [ - 'query-count', - { - title: 'Total Running Queries over last 12 hours (query / 5 minutes)', - interval: 'toStartOfFiveMinutes', - lastHours: 12, - }, - ], ], }, { diff --git a/app/page.tsx b/app/page.tsx index 2b2faa8b..83b036e9 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -2,6 +2,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { ChartAvgMemory } from '@/components/charts/avg-memory' import ChartMergeCount from '@/components/charts/merge-count' import { ChartQueryCountByUser } from '@/components/charts/query-count-by-user' +import ChartTopTableSize from '@/components/charts/top-table-size' import { IntervalSelect } from '@/components/interval-select' export default function Home() { @@ -18,18 +19,19 @@ export default function Home() { -
+
- + +
diff --git a/components/charts/avg-memory.tsx b/components/charts/avg-memory.tsx index 2470c0f4..d1bd846f 100644 --- a/components/charts/avg-memory.tsx +++ b/components/charts/avg-memory.tsx @@ -8,6 +8,7 @@ import { ChartCard } from '../chart-card' export async function ChartAvgMemory({ title, interval = 'toStartOfTenMinutes', + lastHours = 24, className, chartClassName, }: ChartProps) { @@ -16,7 +17,7 @@ export async function ChartAvgMemory({ avg(CurrentMetric_MemoryTracking) AS avg_memory, formatReadableSize(avg_memory) AS readable_avg_memory FROM system.metric_log - WHERE event_time >= (now() - INTERVAL 1 DAY) + WHERE event_time >= (now() - INTERVAL ${lastHours} HOUR) GROUP BY 1 ORDER BY 1 ASC `) diff --git a/components/charts/merge-count.tsx b/components/charts/merge-count.tsx index b5bc3486..1f22d299 100644 --- a/components/charts/merge-count.tsx +++ b/components/charts/merge-count.tsx @@ -14,7 +14,7 @@ export async function ChartMergeCountSpark({ const data = await fetchData(` SELECT ${interval}(event_time) AS event_time, avg(CurrentMetric_Merge) AS avg_CurrentMetric_Merge, - avg(ProfileEvent_MergedRows) AS avg_ProfileEvent_MergedRows + avg(CurrentMetric_PartMutation) AS avg_CurrentMetric_PartMutation FROM system.metric_log WHERE event_time >= (now() - INTERVAL ${lastHours} HOUR) GROUP BY 1 @@ -29,7 +29,7 @@ export async function ChartMergeCountSpark({ index="event_time" categories={[ 'avg_CurrentMetric_Merge', - 'avg_ProfileEvent_MergedRows', + 'avg_CurrentMetric_PartMutation', ]} readable="quantity" stack diff --git a/components/charts/top-table-size.tsx b/components/charts/top-table-size.tsx new file mode 100644 index 00000000..3f728226 --- /dev/null +++ b/components/charts/top-table-size.tsx @@ -0,0 +1,92 @@ +import { fetchData } from '@/lib/clickhouse' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { ChartCard } from '@/components/chart-card' +import type { ChartProps } from '@/components/charts/chart-props' +import { BarList } from '@/components/tremor' + +export async function ChartTopTableSize({ + title, + className, + ...props +}: ChartProps) { + const limit = 7 + const topBySizeQuery = fetchData(` + SELECT + (database || '.' || table) as table, + sum(data_compressed_bytes) as compressed_bytes, + sum(data_uncompressed_bytes) AS uncompressed_bytes, + formatReadableSize(compressed_bytes) AS compressed, + formatReadableSize(uncompressed_bytes) AS uncompressed, + round(uncompressed_bytes / compressed_bytes, 2) AS compr_rate, + sum(rows) AS total_rows, + formatReadableQuantity(sum(rows)) AS readable_total_rows, + count() AS part_count + FROM system.parts + WHERE (active = 1) AND (database != 'system') AND (table LIKE '%') + GROUP BY 1 + ORDER BY compressed_bytes DESC + LIMIT ${limit} + `) + + const topByRowCountQuery = fetchData(` + SELECT + (database || '.' || table) as table, + sum(data_compressed_bytes) as compressed_bytes, + sum(data_uncompressed_bytes) AS uncompressed_bytes, + formatReadableSize(compressed_bytes) AS compressed, + formatReadableSize(uncompressed_bytes) AS uncompressed, + round(uncompressed_bytes / compressed_bytes, 2) AS compr_rate, + sum(rows) AS total_rows, + formatReadableQuantity(sum(rows)) AS readable_total_rows, + count() AS part_count + FROM system.parts + WHERE (active = 1) AND (database != 'system') AND (table LIKE '%') + GROUP BY 1 + ORDER BY total_rows DESC + LIMIT ${limit} + `) + + const [topBySize, topByRowCount] = await Promise.all([ + topBySizeQuery, + topByRowCountQuery, + ]) + + const dataTopBySize = topBySize.map((row) => ({ + name: row.table, + value: row.compressed_bytes, + compressed: row.compressed, + })) + + const dataTopByCount = topByRowCount.map((row) => ({ + name: row.table, + value: row.total_rows, + readable_total_rows: row.readable_total_rows, + })) + + return ( + + + + Top tables by Size + Top tables by Row Count + + + + + + + + + + ) +} + +export default ChartTopTableSize diff --git a/components/data-table/cell.tsx b/components/data-table/cell.tsx index ef8910ab..36af3210 100644 --- a/components/data-table/cell.tsx +++ b/components/data-table/cell.tsx @@ -19,12 +19,18 @@ import { } from '@/components/ui/dropdown-menu' import { ColumnFormat } from '@/components/data-table/columns' +const CODE_TRUNCATE_LENGTH = 50 + export const formatCell = (row: any, value: any, format: ColumnFormat) => { switch (format) { case ColumnFormat.Code: return {value} case ColumnFormat.CodeToggle: + if (value.length < CODE_TRUNCATE_LENGTH) { + return {value} + } + return ( diff --git a/components/header.tsx b/components/header.tsx index 0e3ca670..557ff160 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -7,7 +7,7 @@ export function Header() { return (
-

+

) } + +export interface BarListProps extends TremorBarListProps { + data: (TremorBarListProps['data'][0] & { [key: string]: any })[] + formatedColumn?: string +} + +export function BarList({ data, formatedColumn, ...props }: BarListProps) { + let valueFormatter + + if (formatedColumn) { + valueFormatter = (value: number) => { + const formated = data.find((d) => d.value === value)?.[ + formatedColumn + ] as string + + return formated ? formated : value + } + } + + return ( + + ) +}