Skip to content

Commit

Permalink
top sql: ux refinement (#1122)
Browse files Browse the repository at this point in the history
  • Loading branch information
shhdgit authored Jan 6, 2022
1 parent d02b6af commit eb70e31
Show file tree
Hide file tree
Showing 16 changed files with 584 additions and 301 deletions.
13 changes: 9 additions & 4 deletions pkg/apiserver/topsql/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,15 @@ type SummaryResponse struct {
}

type SummaryItem struct {
SQLDigest string `json:"sql_digest"`
SQLText string `json:"sql_text"`
IsOther bool `json:"is_other"`
Plans []SummaryPlanItem `json:"plans"`
SQLDigest string `json:"sql_digest"`
SQLText string `json:"sql_text"`
IsOther bool `json:"is_other"`
CPUTimeMs uint64 `json:"cpu_time_ms"`
ExecCountPerSec float64 `json:"exec_count_per_sec"`
DurationPerExecMs float64 `json:"duration_per_exec_ms"`
ScanRecordsPerSec float64 `json:"scan_records_per_sec"`
ScanIndexesPerSec float64 `json:"scan_indexes_per_sec"`
Plans []SummaryPlanItem `json:"plans"`
}

type SummaryPlanItem struct {
Expand Down
8 changes: 4 additions & 4 deletions ui/lib/apps/TopSQL/components/Filter/InstanceSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface InstanceGroup {
export interface InstanceSelectProps {
value: TopsqlInstanceItem
onChange: (instance: TopsqlInstanceItem) => void
timeRange: TimeRange
queryTimestampRange: [number, number]
disabled?: boolean
}

Expand All @@ -36,17 +36,17 @@ const splitSelectValue = (v: string): TopsqlInstanceItem => {
export function InstanceSelect({
value,
onChange,
timeRange,
queryTimestampRange,
disabled = false,
}: InstanceSelectProps) {
const { data, isLoading, sendRequest } = useClientRequest(() => {
const [start, end] = calcTimeRange(timeRange)
const [start, end] = queryTimestampRange
return client.getInstance().topsqlInstancesGet(String(end), String(start))
})

useEffect(() => {
sendRequest()
}, [timeRange])
}, [queryTimestampRange])

const instances = data?.data
const instanceGroups: InstanceGroup[] = useMemo(() => {
Expand Down
149 changes: 125 additions & 24 deletions ui/lib/apps/TopSQL/pages/List/List.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { XYBrushArea, BrushEndListener } from '@elastic/charts'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { Space, Button, Spin, Alert, Tooltip, Drawer } from 'antd'
import { Space, Button, Spin, Alert, Tooltip, Drawer, Result } from 'antd'
import {
ZoomOutOutlined,
LoadingOutlined,
Expand All @@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next'

import '@elastic/charts/dist/theme_only_light.css'

import formatSql from '@lib/utils/sqlFormatter'
import client, { TopsqlInstanceItem, TopsqlSummaryItem } from '@lib/client'
import { useLocalStorageState } from '@lib/utils/useLocalStorageState'
import {
Expand All @@ -29,21 +30,18 @@ import { ListTable } from './ListTable'
import { ListChart } from './ListChart'
import { createUseTimeWindowSize } from '../../utils/useTimeWindowSize'
import { SettingsForm } from './SettingsForm'
import { onLegendItemOver, onLegendItemOut } from './legendAction'
import { InstanceType } from './ListDetail/ListDetailTable'

const autoRefreshOptions = [15, 30, 60, 2 * 60, 5 * 60, 10 * 60]
const autoRefreshOptions = [30, 60, 2 * 60, 5 * 60, 10 * 60]
const zoomOutRate = 0.5
const useTimeWindowSize = createUseTimeWindowSize(8)
const topN = 5

export function TopSQLList() {
const { t } = useTranslation()
const {
data: topSQLConfig,
isLoading: isConfigLoading,
sendRequest: updateConfig,
} = useClientRequest((reqConfig) =>
client.getInstance().topsqlConfigGet(reqConfig)
)
const { topSQLConfig, isConfigLoading, updateConfig, haveHistoryData } =
useTopSQLConfig()
const [showSettings, setShowSettings] = useState(false)
const [remainingRefreshSeconds, setRemainingRefreshSeconds] = useState(0)
const [autoRefreshSeconds, setAutoRefreshSeconds] = useLocalStorageState(
Expand Down Expand Up @@ -109,7 +107,15 @@ export function TopSQLList() {
}

const tr = v.x.map((d) => d / 1000)
if (tr[1] - tr[0] < 60) {
const delta = tr[1] - tr[0]
if (delta < 60) {
const offset = Math.floor(delta / 2)
const start = tr[0] + offset - 30
const end = tr[1] - offset + 30
setTimeRange({
type: 'absolute',
value: [Math.ceil(start), Math.floor(end)],
})
return
}

Expand All @@ -132,27 +138,37 @@ export function TopSQLList() {
setTimeRange({ type: 'absolute', value: [computedStart, computedEnd] })
}, [timeRange])

const chartRef = useRef<any>(null)

return (
<>
<div className={styles.container} ref={containerRef}>
{!isConfigLoading && !topSQLConfig?.enable && (
<Card noMarginBottom>
<Alert
message={t(`topsql.alert_header.title`)}
description={t(`topsql.alert_header.body`)}
description={
<>
{t(`topsql.alert_header.body`)}
<a onClick={() => setShowSettings(true)}>
{t('topsql.alert_header.settings')}
</a>
</>
}
type="info"
showIcon
/>
</Card>
)}

<Card noMarginBottom>
<Toolbar>
<Space>
<InstanceSelect
value={instance}
onChange={setInstance}
disabled={isLoading}
timeRange={timeRange}
queryTimestampRange={queryTimestampRange}
/>
<Button.Group>
<TimeRangeSelector
Expand Down Expand Up @@ -189,16 +205,43 @@ export function TopSQLList() {
</Space>
</Toolbar>
</Card>
<div className={styles.chart_container}>
<ListChart
onBrushEnd={handleBrushEnd}
data={topSQLData}
timeRangeTimestamp={queryTimestampRange}
timeWindowSize={timeWindowSize}

{!isConfigLoading && !topSQLConfig?.enable && !haveHistoryData ? (
<Result
title={t('topsql.settings.disabled_result.title')}
subTitle={t('topsql.settings.disabled_result.sub_title')}
extra={
<Button type="primary" onClick={() => setShowSettings(true)}>
{t('conprof.settings.open_settings')}
</Button>
}
/>
</div>
{!!topSQLData?.length && <ListTable topN={topN} data={topSQLData} />}
) : (
<>
<div className={styles.chart_container}>
<ListChart
onBrushEnd={handleBrushEnd}
data={topSQLData}
timeRangeTimestamp={queryTimestampRange}
timeWindowSize={timeWindowSize}
ref={chartRef}
/>
</div>
{!!topSQLData?.length && (
<ListTable
onRowOver={(key: string) =>
onLegendItemOver(chartRef.current, key)
}
onRowLeave={() => onLegendItemOut(chartRef.current)}
topN={topN}
instanceType={instance.instance_type as InstanceType}
data={topSQLData}
/>
)}
</>
)}
</div>

<Drawer
title={t('statement.settings.title')}
width={300}
Expand Down Expand Up @@ -259,11 +302,18 @@ const useTopSQLData = ({
// Sort data by digest
// If this digest occurs continuously on the timeline, we can easily see the sequential overhead
data.sort((a, b) => a.sql_digest?.localeCompare(b.sql_digest!) || 0)

data.forEach((d) => {
d.plans?.forEach(
(item) =>
(item.timestamp_sec = item.timestamp_sec?.map((t) => t * 1000))
)
d.sql_text = formatSql(d.sql_text)
d.plans?.forEach((item) => {
// Filter empty cpu time data
item.timestamp_sec = item.timestamp_sec?.filter(
(_, index) => !!item.cpu_time_ms?.[index]
)
item.cpu_time_ms = item.cpu_time_ms?.filter((c) => !!c)

item.timestamp_sec = item.timestamp_sec?.map((t) => t * 1000)
})
})

setTopSQLData(data)
Expand All @@ -272,3 +322,54 @@ const useTopSQLData = ({

return { topSQLData, updateTopSQLData, isLoading, queryTimestampRange }
}

const useTopSQLConfig = () => {
const {
data: topSQLConfig,
isLoading: isConfigLoading,
sendRequest: updateConfig,
} = useClientRequest((reqConfig) =>
client.getInstance().topsqlConfigGet(reqConfig)
)
const [haveHistoryData, setHaveHistoryData] = useState(true)
const [loadingHistory, setLoadingHistory] = useState(true)

useEffect(() => {
if (!topSQLConfig) {
return
}

if (!!topSQLConfig.enable) {
setLoadingHistory(false)
return
}

;(async function () {
const now = Date.now() / 1000
const sevenDaysAgo = now - 7 * 24 * 60 * 60
// const sevenDaysAgo = now - 60

setLoadingHistory(true)
try {
const res = await client
.getInstance()
.topsqlInstancesGet(String(now), String(sevenDaysAgo))
const data = res.data.data
if (!!data?.length) {
setHaveHistoryData(true)
} else {
setHaveHistoryData(false)
}
} finally {
setLoadingHistory(false)
}
})()
}, [topSQLConfig])

return {
topSQLConfig,
isConfigLoading: isConfigLoading || loadingHistory,
updateConfig,
haveHistoryData,
}
}
Loading

0 comments on commit eb70e31

Please sign in to comment.