Skip to content
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

fix(native filters): rendering performance improvement by reduce overrendering #25901

Merged
merged 4 commits into from
Nov 20, 2023

Conversation

justinpark
Copy link
Member

@justinpark justinpark commented Nov 8, 2023

SUMMARY

Following up #25282, rendering performance can still be improved by reducing unnecessary rerenders (also known as over-rendering).
This commit improves performance in four areas.

1. Inefficient uniqWith and object equality check in uniqueOptions

const uniqueOptions = useMemo(() => {
const allOptions = [...data];
return uniqWith(allOptions, isEqual).map(row => {
const [value] = groupby.map(col => row[col]);

Screenshot 2023-11-01 at 1 48 34 PM

To get the list of unique values, it compares the entire data list (arrayIncludesWith) using object equality comparison (isEqual). This is slow because the data contains several attributes, and object equality comparison is slow.

As it shown in the above metric, uniqueOptions operation triggers four times every time a filter component re-renders, which takes more than 2 seconds per re-render for 10 filters (i.e. 50ms * 4 * 10 filters = 2s).

Using a hashmap approach (with unnecessary equality check) reduced the delay from ~200m(=50ms * 4) to 10ms (95% reduction)
Screenshot 2023-11-01 at 1 47 15 PM

2. Redundant filter re-renders due to the dynamic sizing

Initially renders at a minimum width and then expands to its full width.
native-filter-width-overrendering

Since the native filter's allocated to 100% of its width using SuperChart, which is wrapped by @vx/responsive, it triggers re-renders every time the screen size is updated.
This commit removes the resize observer (by assigning the static width) and updates the filter component wrapper to the full width using CSS instead. As a result, the filters no longer re-render when the page size changes.
native-filter-css-width

3. descendants over-rendering

React's inherent behavior of rerendering all descendant components, coupled with the Redux container's rerendering upon state changes, leads to excessive rerendering of dashboard components, including filter components, whenever the chart fetch status updates the Redux store.
This commit replaces DashboardBuilder to the identical descendant (props.children) which prevents the rerenders when the container component rerenders.
To further optimize performance, the dashboard state synchronization logic was moved to a separate component, effectively decoupling it from the DashboardPage component and preventing unnecessary rerenders of the DashboardPage.

4. Redundant __cache attribute

Due to superfluous setDataMask calls triggered by __cache update, each setState update causes four unnecessary uniqWith executions
fix_native_filters___rendering_performance_improvement_by_reduce_overrendering_by_justinpark_·Pull_Request__25901·_apache_superset

An unnecessary __cache value was introduced in the SelectFilterPlugin in PR#14869, but it was never utilized and resulted in superfluous rerenders of filter components.
This commit removes this redundant __cache value to resolve the problem.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Successfully optimized the application's performance, resulting in a 10% decrease in rendering count (255 to 228) and a remarkable 60% reduction in loading time (10.9 seconds to 4.5 seconds).

Before After
Screenshot 2023-11-07 at 3 57 28 PM Screenshot 2023-11-07 at 3 58 18 PM

TESTING INSTRUCTIONS

  1. Go to any dashboard
  2. Add more than 10 select filters
  3. Reload dashboard
  4. See that filters take a lot of time for before render.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@rusackas
Copy link
Member

rusackas commented Nov 8, 2023

CC @kgabryje who has looked into this sort of thing in this area before.

});
};

const SyncDashboardState: React.FC<Props> = ({ dashboardPageId }) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be a hook rather than a component?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason is related to the topic no.3 3. descendants over-rendering

To further optimize performance, the dashboard state synchronization logic was moved to a separate component, effectively decoupling it from the DashboardPage component and preventing unnecessary rerenders of the DashboardPage.

  • In order to observe state updates and sync them to local storage, it is necessary to include a component with the hook. The most effective approach would be to implement a middleware. In this case, it is skipped to minimize any potential regression.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thank you for explanation!

@@ -322,7 +323,7 @@ const FilterValue: React.FC<FilterControlProps> = ({
) : (
<SuperChart
height={HEIGHT}
width="100%"
width={RESPONSIVE_WIDTH}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the advantage of using this RESPONSIVE_WIDTH instead of 100%?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RESPONSE_WIDTH change is related to the topic no.2 (2. Redundant filter re-renders due to the dynamic sizing)

@kgabryje
Copy link
Member

Amazing improvement! Left 2 minor comments for the code.
As often is the case in such refactors, there's a high risk of introducing regressions. Is there any chance we could get some QA help @sadpandajoe @jinghua-qa ?

@kgabryje
Copy link
Member

/testenv up

Copy link
Contributor

@kgabryje Ephemeral environment spinning up at http://35.87.180.132:8080. Credentials are admin/admin. Please allow several minutes for bootstrapping and startup.

@jinghua-qa
Copy link
Member

Amazing improvement! Left 2 minor comments for the code. As often is the case in such refactors, there's a high risk of introducing regressions. Is there any chance we could get some QA help @sadpandajoe @jinghua-qa ?

I will take a look for the regression

@jinghua-qa
Copy link
Member

Do some regression test around native filter , did not find issues, LGTM

@kgabryje
Copy link
Member

Thanks @jinghua-qa! @justinpark Would you rather address my comments in this PR or merge it and do a follow up if needed?

@justinpark
Copy link
Member Author

Thanks jinghua-qa! justinpark Would you rather address my comments in this PR or merge it and do a follow up if needed?

@kgabryje please see my comments.

Copy link
Member

@kgabryje kgabryje left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@justinpark justinpark merged commit e1d73d5 into apache:master Nov 20, 2023
28 checks passed
Copy link
Contributor

Ephemeral environment shutdown and build artifacts deleted.

@michael-s-molina michael-s-molina added the v3.0 Label added by the release manager to track PRs to be included in the 3.0 branch label Nov 20, 2023
michael-s-molina pushed a commit that referenced this pull request Nov 20, 2023
saghatelian added a commit to 10webio/superset that referenced this pull request Nov 27, 2023
* fix(sqllab): reinstate "Force trino client async execution" (apache#25680)

* fix: remove unnecessary redirect (apache#25679)

(cherry picked from commit da42bf2)

* fix(chore): dashboard requests to database equal the number of slices it has (apache#24709)

(cherry picked from commit 75a7431)

* fix: bump to FAB 4.3.9 remove CSP exception (apache#25712)

(cherry picked from commit 8fb0c8d)

* fix(horizontal filter label): show full tooltip with ellipsis (apache#25732)

(cherry picked from commit e4173d9)

* fix: Revert "fix(Charts): Set max row limit + removed the option to use an empty row limit value" (apache#25753)

(cherry picked from commit e2fe967)

* fix: dataset update uniqueness (apache#25756)

(cherry picked from commit c7f8d11)

* fix(sqllab): slow pop datasource query (apache#25741)

(cherry picked from commit 2a2bc82)

* fix: allow for backward compatible errors (apache#25640)

* fix: DB-specific quoting in Jinja macro (apache#25779)

(cherry picked from commit 5659c87)

* fix: Revert "fix: Apply normalization to all dttm columns (apache#25147)" (apache#25801)

* fix: Resolve issue apache#24195 (apache#25804)

(cherry picked from commit 8737a8a)

* fix(SQL field in edit dataset modal): display full sql query (apache#25768)

(cherry picked from commit 1eba712)

* fix(sqllab): infinite fetching status after results are landed (apache#25814)

(cherry picked from commit 3f28eeb)

* fix: Fires onChange when clearing all values of single select (apache#25853)

(cherry picked from commit 8061d5c)

* fix: the temporal x-axis results in a none time_range. (apache#25429)

Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
(cherry picked from commit ae619b1)

* fix(table chart): Show Cell Bars correctly apache#25625 (apache#25707)

(cherry picked from commit 916f7bc)

* fix: remove `update_charts_owners` (apache#25843)

* fix(charts): Time grain is None when dataset uses Jinja (apache#25842)

(cherry picked from commit 7536dd1)

* fix: Saving Mixed Chart with dashboard filter applied breaks adhoc_filter_b (apache#25877)

(cherry picked from commit 268c1dc)

* fix: database version field (apache#25898)

(cherry picked from commit 06ffcd2)

* fix: trino cursor (apache#25897)

(cherry picked from commit cdb18e0)

* chore: Updates CHANGELOG.md for 3.0.2

* fix(trino): allow impersonate_user flag to be imported (apache#25872)

Co-authored-by: John Bodley <4567245+john-bodley@users.noreply.github.com>
(cherry picked from commit 458be8c)

* fix(table): Double percenting ad-hoc percentage metrics (apache#25857)

(cherry picked from commit 784a478)

* fix(sqllab): invalid sanitization on comparison symbol (apache#25903)

(cherry picked from commit 581d3c7)

* fix: update flask-caching to avoid breaking redis cache, solves apache#25339 (apache#25947)

Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>

* fix: always denorm column value before querying values (apache#25919)

* chore(colors): Updating Airbnb brand colors (apache#23619)

(cherry picked from commit 6d8424c)

* fix: naming denomalized to denormalized in helpers.py (apache#25973)

(cherry picked from commit 5def416)

* fix(helm): Restart all related deployments when bootstrap script changed (apache#25703)

* fix(rls): Update text from tables to datasets in RLS modal (apache#25997)

(cherry picked from commit 210f1f8)

* fix: Make Select component fire onChange listener when a selection is pasted in (apache#25993)

(cherry picked from commit 5fccf67)

* fix(explore): redandant force param (apache#25985)

(cherry picked from commit e7a1876)

* chore: Optimize fetching samples logic (apache#25995)

(cherry picked from commit 326ac4a)

* fix(native filters): rendering performance improvement by reduce overrendering (apache#25901)

(cherry picked from commit e1d73d5)

* fix: update FAB to 4.3.10, Azure user info fix (apache#26037)

(cherry picked from commit 628cd34)

* chore: Updates CHANGELOG.md for 3.0.2 (rc2)

---------

Co-authored-by: Rob Moore <giftig@users.noreply.github.com>
Co-authored-by: Igor Khrol <igor.khrol@automattic.com>
Co-authored-by: Stepan <66589759+Always-prog@users.noreply.github.com>
Co-authored-by: Daniel Vaz Gaspar <danielvazgaspar@gmail.com>
Co-authored-by: Ross Mabbett <92495987+rtexelm@users.noreply.github.com>
Co-authored-by: Geido <60598000+geido@users.noreply.github.com>
Co-authored-by: Beto Dealmeida <roberto@dealmeida.net>
Co-authored-by: JUST.in DO IT <justin.park@airbnb.com>
Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
Co-authored-by: John Bodley <4567245+john-bodley@users.noreply.github.com>
Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>
Co-authored-by: mapledan <mapledan829@gmail.com>
Co-authored-by: Arko <90512504+SA-Ark@users.noreply.github.com>
Co-authored-by: Antonio Rivero <38889534+Antonio-RiveroMartnez@users.noreply.github.com>
Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com>
Co-authored-by: Michael S. Molina <michael.s.molina@gmail.com>
Co-authored-by: FGrobelny <150029280+FGrobelny@users.noreply.github.com>
Co-authored-by: Giacomo Barone <46573388+ggbaro@users.noreply.github.com>
Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
Co-authored-by: Hugh A. Miles II <hughmil3s@gmail.com>
Co-authored-by: josedev-union <70741025+josedev-union@users.noreply.github.com>
Co-authored-by: yousoph <sophieyou12@gmail.com>
Co-authored-by: Jack Fragassi <jfragassi98@gmail.com>
josedev-union pushed a commit to Ortege-xyz/studio that referenced this pull request Jan 22, 2024
cccs-rc pushed a commit to CybercentreCanada/superset that referenced this pull request Mar 6, 2024
@mistercrunch mistercrunch added 🍒 3.0.2 🍒 3.0.3 🍒 3.0.4 🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels 🚢 3.1.0 labels Mar 8, 2024
sfirke pushed a commit to sfirke/superset that referenced this pull request Mar 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels size/L v3.0 Label added by the release manager to track PRs to be included in the 3.0 branch 🍒 3.0.2 🍒 3.0.3 🍒 3.0.4 🚢 3.1.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants