swimlane / ngx-datatable

✨ A feature-rich yet lightweight data-table crafted for Angular
http://swimlane.github.io/ngx-datatable/
MIT License
4.63k stars 1.68k forks source link

Very poor performance with large numbers of loaded cells #582

Open PEsteves8 opened 7 years ago

PEsteves8 commented 7 years ago

I'm submitting a ... (check one with "x")

[x] bug report
[x] feature request
[ ] support request

Current behavior In projects using virtual scroll, if the table has dimensions of 20 rows X 20 columns, the performance gets really, really poor when scrolling.

Expected behavior Having 400 loaded cells in a simple table is pretty light and works with no jank. That's not doable with this table. Ideally, performance would be better with a larger number of cells.

Reproduction of the problem

I haven't been able to properly assess the specific cause of the problem. Large quantities of events, too frequent recalcs or something else. I mostly need the fixed headers (both for rows and columns). If the problem is related to heavy processing of stuff that isn't always needed, perhaps allowing to pass an object of options with flags to disable certain behaviors, could help.

What is the motivation / use case for changing the behavior? Tables with a couple of hundreds of loaded cells are frequently needed when displaying large quantities of data.

Please tell us about your environment: Windows 10

amcdnl commented 7 years ago

Virtual Horz Scrolling would be the solution to this. Watch our video talking about virtual scrolling and why its needed. The vertical scrolling is there to accomplish several row issues.

I haven't had a need for it, often I feel if you have that many columns then the user can't consume that data properly to begin with.

PEsteves8 commented 7 years ago

Thanks. I checked it out, it's pretty interesting. So there isn't a more direct way of improving performance? The large number of columns is kind of an actual requirement for a project. I suppose I could try to suggest doing some sort of column "pagination".

Anyway thanks for the project. I'll try to contribute more (I'm still kind of getting started in these things)

amcdnl commented 7 years ago

Horz virtual scrolling is really the only way. Its not easy but you should be able to take the blueprint for the virtual scrolling and apply it.

adammedford commented 7 years ago

I believe this is at least partially related to #464

amcdnl commented 7 years ago

Ya, kinda/not really lol. That one is memory leaks, this one is number of dom loaded on wide tables.

adammedford commented 7 years ago

You're right, I reread the relevant issues and misunderstood the problem here.

TL/DR for someone just getting here: Enable production mode first.

amcdnl commented 7 years ago

I've fixed the memory leak issues too so this should be faster.

professorjoshua commented 7 years ago

I solved the performance issue due to large number of cells with Vertical Scrolling. In doing so I created a new bug. I change the columns and data based on a users input. If I scroll through one set of data and then switching to another set of data the table with the new data is not repainted unless I scroll. I've tried a number of different things to get the table to repaint but have come up short. Any suggestions?

If not then I'll try again with fixed memory leaks and turn off vertical scrolling.

adammedford commented 7 years ago

What change detection strategy are you using? Does one ever update without the other? (As in, columns updating while rows stay the same)

Log your columns and rows on ngDoCheck() to make sure they are actually changing. If ngDoCheck doesn't fire hundreds of times as you move your mouse then it is likely due to OnPush and you can fix it by adding a reference to ChangeDetectorRef and calling changeDetectorRef.markForCheck() after you've updated those values.

professorjoshua commented 7 years ago

The rows and the columns need to change at that same time. I have a drop down list component that fires an event:

<dropdown #temp1 [values]="lookups" (selectedValue)="onNotify($event)">

In the onNotify I change the array for the columns and then call the appropriate API to retrieve the data for those columns. Everything was working well with the exception of the slow response for tables with hundreds of rows. Turning on the vertical scroll resolved the performance issue but created the rendering issue. I've inspected the ngx-datatable in the browser and all of the new fields are there! For some reason they are just not rendered unless I scroll the datatable. If I resize the window so that a horizontal scroll bar appears and then I move the scroll bar the table magically renders.

Are there any examples of how to use the recalculate method? Or would that not help? I'll look into the ChangeDetectorRef and calling changeDetectorRef.markForCheck().

    <ngx-datatable *ngIf="scrollbarV==true" #myTable style="height:400px;" 
                   [rows]="datarows"
                   [columnMode]="'standard'"
                   [columns]="columnproperties"
                   class='material expandable'
                   [selected]="selected"
                   [selectionType]="'single'"
                   [messages]="messages"
                   (activate)="onActivate($event)"
                   (select)='onSelectItem($event)'
                   [loadingIndicator]="loadingIndicator"
                   [scrollbarV]="scrollbarV"   
                   id="lookupdata">         
    </ngx-datatable>
adammedford commented 7 years ago

If you're seeing the rows being added in the page source but not on the page itself then I don't think change detection is the issue. What happens if you set the row heights to a fixed value? I imagine that if your rows are striped you will see the empty rows, indicating that the data of the row cells isn't being populated.

professorjoshua commented 7 years ago

Set the default rowHeight:

    <ngx-datatable *ngIf="scrollbarV==true" #myTable style="height:400px;" 
                   [rows]="datarows"
                   [columnMode]="'standard'"
                   [columns]="columnproperties"
                   class='material expandable'
                   [selected]="selected"
                   [selectionType]="'single'"
                   [messages]="messages"
                   (activate)="onActivate($event)"
                   (select)='onSelectItem($event)'
                   [loadingIndicator]="loadingIndicator"
                   [scrollbarV]="scrollbarV"
                   [rowHeight]="50"   
                   id="lookupdata">         
    </ngx-datatable>

Same issue. It works beautifully if I just change the drop down list. I can even scroll one list and as long as I bring the scroll back to the top the change in the requested table works. It is only when I scroll down, leave the scroll down and then select another table.

adammedford commented 7 years ago

I'd recommend opening a separate issue for your bug to make it easier for the Swimlane team to track it. I will attempt to attempt to reproduce myself once I'm not on deadline.

askdesigners commented 7 years ago

I'm getting laggy but survivable performance on scroll, but I'm loading in about 300 rows with 17-20 columns, and it literally takes about 20-25 seconds to render the table. This is really not survivable.

Is there anyway I can speed up the initial rendering time?? In addition to taking that long, it's also completely locking down the render thread making the page unresponsive in the meantime.

It would suck to have to change components at this point, but if I have to to improve perf I will. :/ Any ideas??

gm112 commented 7 years ago

@askdesigners Turning off the vertical scrollbar helps immensely with performance. Though I wish I could leave scrolling on just so it would work a bit more intuitively.

askdesigners commented 7 years ago

Yes that's what I've ended up with @gm112. It's required for my layout anyways as there's a sticky header with action button above the table.

I will say that rendering performance is still horrific. :/

mhadaily commented 6 years ago

I have the same issue, I have only 10 columns and 43 rows and grouping enabled. it's super slow and laggy even though I have enabled change-detection and disabled scrollbarV. I also notice that memory usage for painting and recalculating the table is super hight which makes the whole application to be slow.

anyway, thanks for your awesome work, the plugin itself is super awesome.

amcdnl commented 6 years ago

@mhadaily - Does this occur when you have Angular set in production mode?

mhadaily commented 6 years ago

@amcdnl Yes. Just FYI, I have deleted all EventListener expect for body scroll, and that helped a lot but it's still very expensive when the table needs to re-render in order to have a new column. Performance on Safari is better but in Chrome, FF and Edge is very poor.

Profiling shows that Event listeners are the most memory and CPU consuming apparently.Also, the memory will go higher and higher as you continue working with the table and makes the application work slower. I don't have ScrollbarV but I do have ScrollBarH. I believe recalculating dims and columns as well as attaching event listeners could cause this issue as I could improve performance by just removing them. Unfortunately, I didn't have more time to debug more, but I would be more than happy if I can help you guys to understand what the issue is and probably send a PR to resolve it.

Please do let me know if you need more information or help.