-
Notifications
You must be signed in to change notification settings - Fork 14.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf(dashboard): make loading datasets non-blocking #15699
Conversation
@@ -43,53 +43,38 @@ export type ControlProps = { | |||
renderTrigger?: boolean; | |||
}; | |||
|
|||
export default class Control extends React.PureComponent< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactor from class component to functional. Not related to this PR but may be useful in the future.
df6860d
to
92fda2d
Compare
Codecov Report
@@ Coverage Diff @@
## master #15699 +/- ##
=======================================
Coverage 76.82% 76.83%
=======================================
Files 983 983
Lines 51585 51581 -4
Branches 6974 6979 +5
=======================================
Hits 39632 39632
+ Misses 11729 11727 -2
+ Partials 224 222 -2
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
21d3e92
to
e3ccef1
Compare
} | ||
|
||
export const FETCH_DATASOURCE_FAILED = 'FETCH_DATASOURCE_FAILED'; | ||
export function fetchDatasourceFailed(error, key) { | ||
return { type: FETCH_DATASOURCE_FAILED, error, key }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleaned up FETCH_DATASOURCE_STARTED
and FETCH_DATASOURCE_FAILED
because there are no corresponding reducers for them.
@@ -19,7 +19,7 @@ | |||
import Owner from './Owner'; | |||
import Role from './Role'; | |||
|
|||
type Dashboard = { | |||
export interface Dashboard { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this change for? Dashboard doesn't have methods why prefer interface?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interface is always preferred other than in React props.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fwiw i think there's still a bunch of discrepancies across Superset for this. I don't really care one way or another (consistency is better in my mind) but noting that even after this change there will still be a bunch of inconsistencies
this is a reasonable trade-off we can try. Is it possible that filter_box started query before dataset metadata is not ready, will that cause any issue? |
Time Column and Granularity control in filter boxes may not have select choices. Filter indicators may show inexplicable filter values. But those are expected to be temporary and not very noticeable. In case datasets loading fails, in previous case, the whole page won't render, while after this change you still have a largely functional Dashboard page. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested with native filters and with datasets hardcoded to null - everything works perfectly fine, including filters and filter indicators. The only difference is that we can't create a new native filter as it requires selecting a dataset; we can use the already existing native filters though. LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for the performance and typescript improvements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a few nits, but nothing blocking. thanks for tackling this work so quickly!
|
||
// gets the datasets for a dashboard | ||
// important: this endpoint only returns the fields in the dataset | ||
// that are necessary for rendering the given dashboard | ||
export const useDashboardDatasets = (idOrSlug: string | number) => | ||
useApiV1Resource(`/api/v1/dashboard/${idOrSlug}/datasets`); | ||
useApiV1Resource<Datasource[]>(`/api/v1/dashboard/${idOrSlug}/datasets`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: perhaps we should rename the Datasource type to Dataset? Or at least alias it for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are many places where the Datasource/Dataset type is defined---including two places in superset-ui
. I think we need a separate PR to consolidate those. Although they do have small differences depending on the context.
this.setState({ hovered }); | ||
const ControlComponent = typeof type === 'string' ? controlMap[type] : type; | ||
if (!ControlComponent) { | ||
return <>Unknown controlType: {type}</>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need a fragment here? Couldn't this be:
return <>Unknown controlType: {type}</>; | |
return `Unknown controlType: ${type}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React typing would complain if returning a plain string. Something about expecting a ComponentType to always return ReactElement.
@@ -19,7 +19,7 @@ | |||
import Owner from './Owner'; | |||
import Role from './Role'; | |||
|
|||
type Dashboard = { | |||
export interface Dashboard { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fwiw i think there's still a bunch of discrepancies across Superset for this. I don't really care one way or another (consistency is better in my mind) but noting that even after this change there will still be a bunch of inconsistencies
Have we verified yet that none of the chart plugins use datasets? If so we should also stop passing datasets to the charts. If any of the plugins do use datasets, this might break them. |
Thanks for pointing this out. I did more vetting and realized that some charts do use info on Fixed a re-render issue now that charts will be updated accordingly once datasets are loaded: chart-rerender.mp4Notice the name of the first column. It uses |
SUMMARY
This will be one of the many PRs to address perf issues raised in #15518 .
Currently the Dashboard page will wait for both
datasets
andcharts
data to start rendering, however the datasets data are only used in filter indicators and filter boxes and should not block us from rendering other charts. In our case, thedatasets
endpoint is often much slower because we have a giant single-source-of-truth datasource with thousands of metrics and columns.Unblocking rendering from the datasets endpoint should speed up the page rendering a little bit. In our use case, it's often a matter of a full second.
It's not easy to simply remove
datasources
from Dashboard state as that would involve letting the filter indicators and filter box fetching datasource metadata themselves.BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
Before
Dashboard renders after
/datasets
is loaded:before-pr.mp4
After
Dashboard renders as soon as
/dashboard/[id]
and/dashboard/[id]/charts
are loaded:after-pr.mp4
TESTING INSTRUCTIONS
Go to dashboard page, make sure everything still renders correctly.
ADDITIONAL INFORMATION