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

[Discover] Fix performance regression in sidebar #109999

Conversation

kertal
Copy link
Member

@kertal kertal commented Aug 25, 2021

Summary

This PR fixes a performance regression in Discover sidebar introduced in 7.14 when searching the sidebar containing lots of fields that need to be grouped (so it's not just the number of fields, but the structure). The function to calculate details displayed in the popover was executed without the popover being displayed. So when 25 fields were displayed, it was calculated 25 times (luckily we just render the fields that are visible to the user). What's more calc_field_count had redundant executions, which also worsens performance.

Discover_-Elastic_und_Discover-_Elastic

Here's an example how the performance profile looked like on a system with performance problems:

Discover_-_Elastic

Testing

I'm adding a files (sidebar-stress.zip) so you can reproduce it. You can use it to provision 500 records with a structure to trigger the performance troubles.

Before that you need to configure the created index so it can contain lot's of fields by running

PUT sidebar-search-test
{
  "settings": {"index.mapping.total_fields.limit": 4000}
}

When ingested, you need to create an index pattern for sidebar-search-test, go to Discover, search in the sidebar, this should no longer be very, very slow.

fixes #109998

Checklist

@kertal kertal added Feature:Discover Discover Application release_note:fix Team:Visualizations Visualization editors, elastic-charts and infrastructure v8.0.0 v7.15.0 v7.14.1 labels Aug 25, 2021
@kertal kertal self-assigned this Aug 25, 2021
@kertal kertal marked this pull request as ready for review August 25, 2021 09:05
@kertal kertal requested a review from a team August 25, 2021 09:05
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app (Team:KibanaApp)

@kertal
Copy link
Member Author

kertal commented Aug 25, 2021

@elasticmachine merge upstream

@kertal kertal requested a review from majagrubic August 25, 2021 09:36
@rashmivkulkarni
Copy link
Contributor

@kertal - its already past FF for 7.14.1 , but bug fixes are still ok , Do you think it will make it or move the label to 7.14.2 ?

kertal added 2 commits August 25, 2021 23:40
…of github.com:kertal/kibana into kertal-pr-2021-08-25-discover-fix-sidebar-performance
@kertal
Copy link
Member Author

kertal commented Aug 26, 2021

@rashmivkulkarni it would be neat to fix this in 7.14.1, I see the tag is not available now, so let's see if I can make it today

@@ -15,6 +15,11 @@ import { IndexPatternField } from '../../../../../../../data/public';
import { stubIndexPattern } from '../../../../../../../data/common/stubs';

jest.mock('../../../../../kibana_services', () => ({
getUiActions: jest.fn(() => {
Copy link
Member Author

Choose a reason for hiding this comment

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

less error messages when executing the test

Comment on lines +124 to +130
if (fieldCounts.current === null) {
fieldCounts.current = calcFieldCounts(
{},
props.documents$.getValue().result,
props.selectedIndexPattern
);
}
Copy link
Member Author

@kertal kertal Aug 26, 2021

Choose a reason for hiding this comment

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

make surecalcFieldCounts is just executed once

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can be moved to useEffect, before subscription, which should initialized after mounting

@kertal kertal added the auto-backport Deprecated - use backport:version if exact versions are needed label Aug 26, 2021
@@ -358,7 +358,36 @@ function DiscoverFieldComponent({
</EuiPopoverTitle>
);

const details = getDetails(field);
const renderPopover = () => {
const details = getDetails(field);
Copy link
Member Author

Choose a reason for hiding this comment

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

making sure getDetails is just executed when needed (popover is displayed)

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
discover 567.4KB 567.5KB +104.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @kertal


const [documentState, setDocumentState] = useState(props.documents$.getValue());
useEffect(() => {
const subscription = props.documents$.subscribe((next) => {
if (next.fetchStatus !== documentState.fetchStatus) {
if (next.result) {
fieldCounts.current = calcFieldCounts(
next.result.length ? fieldCounts.current : {},
next.result.length && fieldCounts.current ? fieldCounts.current : {},
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still having trouble understanding this logic. we're calculating fieldCounts, passing in the value that we got as a result of passing in the previous result of calcFieldCounts?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, it's like it behaved for a long time, didn't change, but I think it should be in the future.

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe this logic needs some revisiting, but after testing I don't think it's broken. Let's see if we can do some cleanup here in a follow-up PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

👍 wanna add an issue for that?

Copy link
Contributor

@majagrubic majagrubic left a comment

Choose a reason for hiding this comment

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

Tested in Chrome on Mac OSX, can confirm that functionality-wise it works same as before. Haven't done a detailed profiling on performance optimization, but it seems pretty clear from the code.

@kertal kertal added the v7.16.0 label Aug 26, 2021
@kertal kertal merged commit dc07f4d into elastic:master Aug 26, 2021
@kibanamachine
Copy link
Contributor

💔 Backport failed

Status Branch Result
7.15 Commit could not be cherrypicked due to conflicts
7.x
7.14 Commit could not be cherrypicked due to conflicts

Successful backport PRs will be merged automatically after passing CI.

To backport manually run:
node scripts/backport --pr 109999

Copy link
Contributor

@dimaanj dimaanj left a comment

Choose a reason for hiding this comment

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

LGTM, tested in Chrome. One of the thing should be changed in follow up PR here is subscription after mounting.

props.documents$.getValue().result,
props.selectedIndexPattern
);
}

const [documentState, setDocumentState] = useState(props.documents$.getValue());
useEffect(() => {
const subscription = props.documents$.subscribe((next) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

documentState dependency change leads to initializing subscription two times. So the first listener will not be cleaned up, but I guess it was before.

Comment on lines +124 to +130
if (fieldCounts.current === null) {
fieldCounts.current = calcFieldCounts(
{},
props.documents$.getValue().result,
props.selectedIndexPattern
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can be moved to useEffect, before subscription, which should initialized after mounting

kibanamachine added a commit that referenced this pull request Aug 26, 2021
kertal added a commit to kertal/kibana that referenced this pull request Aug 26, 2021
# Conflicts:
#	src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.test.tsx
kertal added a commit to kertal/kibana that referenced this pull request Aug 26, 2021
# Conflicts:
#	src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.test.tsx
#	src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx
kertal added a commit that referenced this pull request Aug 26, 2021
# Conflicts:
#	src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.test.tsx
#	src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.tsx
kertal added a commit that referenced this pull request Aug 26, 2021
# Conflicts:
#	src/plugins/discover/public/application/apps/main/components/sidebar/discover_sidebar_responsive.test.tsx
@LeeDr LeeDr added v7.14.2 and removed v7.14.1 labels Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed Feature:Discover Discover Application performance release_note:fix Team:Visualizations Visualization editors, elastic-charts and infrastructure v7.14.2 v7.15.0 v7.16.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Discover] Sidebar search performance regression
7 participants