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

b-table: Performance drops whenever more than a few thousand cells are rendered #4155

Closed
jaylittle opened this issue Sep 25, 2019 · 27 comments · Fixed by #4213
Closed

b-table: Performance drops whenever more than a few thousand cells are rendered #4155

jaylittle opened this issue Sep 25, 2019 · 27 comments · Fixed by #4213

Comments

@jaylittle
Copy link

jaylittle commented Sep 25, 2019

Describe the bug

When attempting to render more than a few thousand cells in b-table, rendering performance and general vue performance seem to drop off quite noticeably resulting in a poor user experience.

Steps to reproduce the bug

  1. Create a b-table that renders at least 100 records of data with at least 10 columns of data.
  2. After the table renders the records, vue processing performance appears to be degraded significantly (e.g. other bound input controls on the component hosting b-table).
  3. There is a very noticeable lag between when the provider returns the data array and when the refreshed event for b-table fires.
  4. There is also a noticeable lag between when the refreshed event for b-table fires and when the actual table appears to be fully rendered with the new data.
  5. The more times the provider returns data, the worse performance seems to get.

Expected behavior

  1. b-table should render cells quicker than the half a second it currently takes in Chrome with 500 rows and 13 cells my example runs for.
  2. Lag between refreshed event being fired and b-table completing its rendering process should be reduced.
  3. Vue processing performance for other bound input controls in the same hosting component should be non-existent.
  4. Subsequent calls to the provider should not degrade performance in any way.

Versions

Libraries:

  • BootstrapVue: 2.0.2
  • Bootstrap: 4.3.1
  • Vue: 2.6.10

Environment:

  • Device: Intel x86 Laptop and Desktop
  • OS: Linux and Windows
  • Browser: Chrome and Firefox
  • Version: Latest

Demo link

https://jsfiddle.net/ke3f2whb/1/

Demo allows user to modify row count using bound text box. Default row count is set to 500. Column count is set to 13.

Additional context

This was not an issue in 2.0.0rc26 but is definitely an issue in 2.0.0, 2.0.1 and 2.0.2. I can't speak for in-between versions as I have not personally tested them. This appears to be a rather severe performance regression and is currently hindering a number of user activities in a production application of mine (yeah, they really wanted floating headers).

In addition this problems also appears to severely degrade route switching performance when the user does something that results in a route change and the current view includes a b-table component with a significant number of rows.

For the time being, I have restricted the maximum number of rows per page in the application to 100, which helps a great deal but when it comes to tables with a larger number of columns, performance is still a problem. Any fixes or assistance you can offer would be most appreciated as my users are putting a lot of pressure on me to resolve the issue.

@tmorehouse
Copy link
Member

tmorehouse commented Sep 25, 2019

Related (possible duplicate): #4150

B-Table is a heavy component which does quite a bit of processing each time something triggers the table to re-render (Vue calls the render function, which then must again process all cells in the table, before it can determine what it needs to patch on the DOM).

There are some things you can do for performance:

  • Ensure your table data has a unique value column (i.e. a primary key), which you can pass the name of that field to the primary-key prop.
  • Paginate your results to limit the number of visible rows rendered (keep it less than 100)
  • If you don't need to advanced features of b-table, use b-table-lite or b-table-simple

@jaylittle
Copy link
Author

jaylittle commented Sep 25, 2019

Any idea what changed here? These performance issues were not present in 2.0.0rc26 and earlier in my experience. Our app uses the same page sizes (500 max) and column counts (between 2 and 15) now as it did two weeks ago when we were running with that version. Is the performance regression here expected given one or more of the new features present in 2.0.0+?

@jaylittle
Copy link
Author

jaylittle commented Sep 25, 2019

Here is a very similar jsfiddle (also removed the frozen header stuff) that makes use of 2.0.0-rc.26 instead of 2.0.2 and as you'll be able to see, it works a lot better. There is still lag on other bound input fields, but other than that the difference is quite noticeable:

https://jsfiddle.net/bvqfo95a/

@jaylittle
Copy link
Author

Here is another jsfiddle that uses 2.0.2, removes the frozen header stuff, adds a primary key and makes use of 2.0.2. Performance is definitely degraded when compared to the rc26 example that doesn't have a primary key set.

https://jsfiddle.net/rmvyqLfu/

@tmorehouse
Copy link
Member

tmorehouse commented Sep 25, 2019

The biggest change was the introduction of the helper components for the rows, cells, etc. Which use inject (from the table component) to simplify the code and to handle sticky header/columns. Each cell is now a Vue instance (needed for inject to work) which can add a bit of overhead (although since they are full component, they are statefull and only re-render when their props/content changes)

@tmorehouse
Copy link
Member

I'll see if we can find a way to improve the provide/inject performance for the child helper components.

@jaylittle
Copy link
Author

Delved into this a bit more today. Created three new jsfiddles. One uses b-table and the other uses b-table-lite in 2.0.2. I have removed the provider from both of them and streamlined the record creation code which I've found better allows us to track the b-table related performance when it comes to actually updating the items. In this particular example, once you remove the provider so that b-table-lite can be used, performance appears to be exactly the same between the two components for 2.0.2 (around 2.4 seconds for the initial data render when hitting "Run" in jsfiddle).

Whereas in the third example doing the exact same thing with b-table in 2.0.0-rc.26 yields far superior performance (around 0.9 seconds for the initial data render when hitting "Run" in jsfiddle).

b-table non-provider 2.0.2 example: https://jsfiddle.net/3nh9qvfk/
b-table-lite non-provider 2.0.2 example: https://jsfiddle.net/adom5cpr/
b-table non-provider 2.0.0-rc.26 example: https://jsfiddle.net/Lxy1zpq5/

@jaylittle
Copy link
Author

jaylittle commented Sep 25, 2019

I guess my initial thought is, can b-table-lite in 2.0.3 possibly be based on the b-table code present in 2.0.0-rc.26? Is that even remotely possible?

EDIT: With the new slot syntax in place of course ;)

@jaylittle
Copy link
Author

jaylittle commented Sep 25, 2019

Also after playing around some more it appears that the performance issue specifically emerged with 2.0.0-rc.28. 2.0.0-rc.27 still ran like a bat out of hell.

Here's a jsfiddle for rc.28: https://jsfiddle.net/8xck9amr/

@tmorehouse
Copy link
Member

tmorehouse commented Sep 28, 2019

@jaylittle Just to confirm, your are saying that 2.0.0-rc.27 doesn't experience the issue, but 2.0.0-rc.28 does?

Just trying to narrow down the code differences in the versions.

@tmorehouse
Copy link
Member

@jaylittle

I guess my initial thought is, can b-table-lite in 2.0.3 possibly be based on the b-table code present in 2.0.0-rc.26? Is that even remotely possible?

BTableLite uses the same mixins as BTable, minus the provider, sorting, etc. They share the same core functionality... just minus the additional features of BTable

@jaylittle
Copy link
Author

@jaylittle Just to confirm, your are saying that 2.0.0-rc.27 doesn't experience the issue, but 2.0.0-rc.28 does?

Just trying to narrow down the code differences in the versions.

2.0.0-rc.27 runs great like 2.0.0-rc.26
2.0.0-rc.28 is sluggish like 2.0.2

@WayneHiller
Copy link

I noticed this on a large table but the rendering was not too bad. Where I really noticed a slow down was when switching to another page via the vue router. Could it be that the slow down is happening when the BTable is being destroyed.

@tmorehouse
Copy link
Member

Depends on if it is really being destroyed, or the props are just being updated, on route change

@WayneHiller
Copy link

WayneHiller commented Oct 2, 2019

Arnt the components on the page always destroyed when changing routes if the page is not inside a <keep-alive>

@tmorehouse
Copy link
Member

tmorehouse commented Oct 2, 2019

Depends on if it is the same page vue component using a slug, etc in the same router-view/nuxt-vue/nuxt-child

If the last path entry in the pages route is a parameter (slug), then it is the same route component, but with new parameters/properties.

@WayneHiller
Copy link

In my case they are different pages. It there anything in the destruction of the table that could cause a slow down like that? Removing Event Handlers etc. It actually took much longer to move to a different page that it took to render the table in the first place. I changed my table to use 20 row paging and now it is lightning fast to render and to move to a new page.

@Stephen9s
Copy link

Stephen9s commented Oct 3, 2019

I see a similar drop in performance just rendering 100 records with 7 different slots. Rendering isn't necessarily slow, but what is slow are inputs, check boxes, and dropdowns. Anything that writes to data is slowed down massively.

I also confirmed that trying 2.0.0.rc-27 did not exhibit the same behavior where inputs, check-boxes, and dropdowns using v-model were slow, but the templates no longer worked for obvious reasons.

@tmorehouse
Copy link
Member

BootstrapVue v2.0.3 has been released, which includes some performance enhancements for tables

@jaylittle
Copy link
Author

jaylittle commented Oct 7, 2019

With 2.0.3 I'm not seeing any improvement over 2.0.2 in my test cases:

b-table non-provider 2.0.3 example: https://jsfiddle.net/qgjte6kL/
b-table-lite non-provider 2.0.3 example: https://jsfiddle.net/6e1v3rpL/

For the time being I have rolled my own application back to 2.0.0.rc-27 in an effort to avoid dealing with this issue in production and users have definitely noticed a difference.

@tmorehouse
Copy link
Member

We'll have to see what else we can do to improve performance (such as only using the helper components when the cell is a sticky header/column)

@Stephen9s
Copy link

I noticed that performance increased a bit, but still has (at least for me), a half second lag when typing or selecting dropdowns.

@tmorehouse
Copy link
Member

PR #4213 (still in the works) Should also improve performance

@jaylittle
Copy link
Author

Oh now THAT is promising.

@tmorehouse
Copy link
Member

Bootstrap v2.0.4 has been released, which includes table render performance improvements

@jaylittle
Copy link
Author

The performance of my b-table example has improved considerably with this new version. Lovely work!

https://jsfiddle.net/o2kr8e0f/

@noges
Copy link

noges commented Jan 21, 2021

I used a custom filter function with a filter-function prop and it's much faster now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants