dataTable rendering too slow

UI Components for JSF
Post Reply
charlietran1986
Posts: 29
Joined: 02 Aug 2020, 20:00

11 Jan 2022, 10:25

Hi guys!
I have a small table with about 200 rows. I use PrimeFaces dataTable to display them, but the rendering is very slow (about 5-6 seconds to fully displayed). Below is my code:
BudgetSource.xhtml

Code: Select all

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                xmlns:p="http://primefaces.org/ui"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:form id="budgetSourceFrm">
        <div>
            <p:outputLabel value="Budge Source" style="font-weight: bold" />
        </div>
        <div style="margin-top: 5px">
            <p:commandButton value="Add" onclick="PF('newBudgetSourceDlg').show()" icon="pi pi-plus" style="text-align: center; margin-right: 30px;" rendered="#{businessBean.task == 8}"/>
            <p:commandButton value="Edit" onclick="PF('editBudgetSourceDlg').show()" icon="pi pi-pencil" style="text-align: center; margin-right: 30px;" rendered="#{businessBean.task == 8}"/>
            <p:commandButton value="Delete" action="#{budgetSourceBean.removeSelected}" styleClass="ui-button-danger" icon="pi pi-trash" style="text-align: center; margin-right: 30px;" oncomplete="PF('budgetSourcesTable').filter()" process="@this" rendered="#{businessBean.task == 8}">
                <p:confirm header="Confirm" message="Delete the record?" icon="pi pi-exclamation-triangle" />
            </p:commandButton>
            <p:commandButton value="Print" icon="pi pi-print" style="text-align: center; margin-right: 30px;" rendered="#{businessBean.task == 8}"/>
        </div>
        <p:dataTable id ="budgetSources" emptyMessage="" draggableColumns="true" resizableColumns="true" resizeMode="expand"  var="bs" widgetVar="budgetSourcesTable" 
                     value="#{budgetSourceController.findAll(sessionInfoBean.currentDatabase)}" rendered="#{businessBean.task == 8}" 
                     filteredValue="#{budgetSourceBean.filteredBudgetSources}" selectionMode="single" sortBy="#{bs.budgetSourceCode}" sortMode="single"
                     selection="#{budgetSourceBean.selectedBudgetSource}" rowKey="#{bs.budgetSourceCode}" showGridlines="true"
                     paginator="true" rows="6" paginatorPosition="bottom"
                     paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                     currentPageReportTemplate="{startRecord}-{endRecord} of {totalRecords} record.">
            <p:ajax event="rowSelect" listener="#{budgetSourceBean.rowSelect}"/>
            <p:ajax event="rowUnselect" listener="#{budgetSourceBean.rowUnSelect}"/>
            <p:column headerText="Code" groupRow="true" filterBy="#{bs.budgetSourceCode}" filterMatchMode="contains" sortBy="#{bs.budgetSourceCode}" sortOrder="asc" style="text-align: left">
                <h:outputText value="#{bs.budgetSourceCode}" />
            </p:column>
            <p:column headerText="Name" filterBy="#{bs.budgetSourceName}" filterMatchMode="contains" sortBy="#{bs.budgetSourceName}" style="text-align: left">
                <h:outputText value="#{bs.budgetSourceName}" />
            </p:column>
            <p:column headerText="Type" filterBy="#{bs.budgetSourceProperty}" filterMatchMode="contains" sortBy="#{bs.budgetSourceProperty}" style="text-align: center">
                <h:outputText value="#{bs.budgetSourceProperty == 0 ? 'Domestic' : 'Foreign'}" style="text-align: left"/>
            </p:column>
            <p:column headerText="Used" style="text-align:center">
                <f:facet name="filter">
                </f:facet>
                <p:selectBooleanCheckbox value="#{bs.active}" disabled="true"/>
            </p:column>
        </p:dataTable>
    </h:form>
    </p:dialog>
</ui:composition>
BudgetSourceController.java

Code: Select all

package com.spf.ibigtime.jpa.dao;

import com.spf.ibigtime.entities.Budgetsource;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

/**
 *
 * @author charlie
 */
@Named
@RequestScoped
public class BudgetSourceController extends Dao<Budgetsource> {

    public List<Budgetsource> findAll(String multitenancyIdentifier) {
        return getEntityManager(multitenancyIdentifier).createNamedQuery("Budgetsource.findAll", Budgetsource.class)
                .getResultList();
    }

    public Budgetsource findByBudgetSourceID(String budgetSourceID, String multitenancyIdentifier) {
        return getEntityManager(multitenancyIdentifier).createNamedQuery("Budgetsource.findByBudgetSourceID", Budgetsource.class).setParameter("budgetSourceID", budgetSourceID)
                .getSingleResult();
    }

    public Budgetsource findByBudgetSourceCode(String budgetSourceCode, String multitenancyIdentifier) {
        return getEntityManager(multitenancyIdentifier).createNamedQuery("Budgetsource.findByBudgetSourceCode", Budgetsource.class).setParameter("budgetSourceCode", budgetSourceCode)
                .getSingleResult();
    }
}
Why the rendering is very slow for such small data table?
PrimeFaces version 11, MySQL server 10.4.21, Glassfish server 5, Jakarta EE 8

charlietran1986
Posts: 29
Joined: 02 Aug 2020, 20:00

11 Jan 2022, 12:31

I use Chrome DevTools to analyze the timing. The timing period was recorded from the moment when button was clicked to the moment when dataTable was fully displayed. It shows very strange plot. Most of spent time is idle time. I have attached the picture below.
https://imgur.com/a/QN510Ec

pangbuddy
Posts: 13
Joined: 01 Apr 2011, 23:27

11 Jan 2022, 15:23

have you measured the time spent in the findAll () method, and it is not a good practice to put logic in the get value method

Melloware
Posts: 3716
Joined: 22 Apr 2013, 15:48

11 Jan 2022, 15:24

You are only rendering 6 rows to start which is very little. I have datatables WAY bigger than this that load very fast. So is it possible the time is being spent in your DB query? Can you elimite the DB and send 200 hard coded records to the UI and is it still slow?

I could be wrong....but I really don't think its the DT rendering that is slow....
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

Melloware
Posts: 3716
Joined: 22 Apr 2013, 15:48

11 Jan 2022, 15:25

I agree with @pangbuddy too. You should add a log statement in your findAll and see if it is being called more than once. JSF has a tendency to call methods more than once during a page render which is why its not recommend to do what you are doing.
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

charlietran1986
Posts: 29
Joined: 02 Aug 2020, 20:00

12 Jan 2022, 09:07

@Melloware
@@pangbuddy
I have found the problem. My main page contains a number of commandlinks, each of them corresponds to a data table needed to display when clicked. I have made one <ui:composition> per each dataTable, and have included all these .xhtml files to the common panel (see the image below). I use an index number to refer to which commandlink was clicked and update the panel upon this index (i.e. conditional rendering). I don't know why JSF tends to reload all these datatables each time I click on one commandlink instead of reload only which one is clicked? How to work around this problem?

contents.xhtml

Code: Select all

.........
<div class="column right">
                <p:panel id ="contentFrame">
                    <ui:insert name = "users" >
                        <ui:include src = "includes/users.xhtml" />
                    </ui:insert>                     
                    <ui:insert name="budgetSources">
                        <ui:include src="includes/category/budgetsources.xhtml" />
                    </ui:insert>
                    <ui:insert name="accountCategory">
                        <ui:include src="includes/category/accountCategories.xhtml"/> 
                    </ui:insert>
                    <ui:insert name="accounts">
                        <ui:include src="includes/category/accounts.xhtml"/> 
                    </ui:insert>
                    <ui:insert name="accountTransfers">
                        <ui:include src="includes/category/accounttransfers.xhtml"/> 
                    </ui:insert>
                    <ui:insert name="reftypes">
                        <ui:include src="includes/category/reftypes.xhtml"/> 
                    </ui:insert>
                    <ui:insert name="autobusiness">
                        <ui:include src="includes/category/autobusiness.xhtml" />
                    </ui:insert>
                    ..... other includes                    
                </p:panel>
            </div>
        </div>
 ..........

https://imgur.com/a/kc1XZQx

Melloware
Posts: 3716
Joined: 22 Apr 2013, 15:48

12 Jan 2022, 15:14

What does your commandlink code look like?
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

charlietran1986
Posts: 29
Joined: 02 Aug 2020, 20:00

13 Jan 2022, 04:17

@Melloware
My commandlinks are inside a tabview, as the code below. When the commandlink is clicked, method 'bussinessBean.setTask()' will be called to set the index number and then 'contentFrame' panel will be updated upon this index.

Code: Select all

<p:tabView>
    <p:tab title="System">
        <p:toolbar>
            <p:toolbarGroup>
            ................................
                <p:commandLink class="cmdlink" action="#{businessBean.setTask(1)}" update=":contentFrm:contentFrame" immediate="true" process="@this">
                    <h:graphicImage name="images/user.png" class="link-image"/>
                    <h:outputText value="Users" class="link-text"/>
                 </p:commandLink>                               
            ...................................                              
            </p:toolbarGroup>
        </p:toolbar>
    </p:tab>
</p:tabView>

Melloware
Posts: 3716
Joined: 22 Apr 2013, 15:48

13 Jan 2022, 21:34

Sorry nothing is standing out to me.
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

User avatar
T.dot
Expert Member
Posts: 620
Joined: 01 Feb 2012, 15:39
Location: Vienna/Austria

14 Jan 2022, 12:10

I would recommend to refactor your code:
- Load the data from DB only once and store it in a variable. Easiest way to do this is:

Code: Select all

public class BackingBean {
  private List<Data> data;

  public List<Data> getData() {
    if (data == null) {
      data = loadMyDataMethod();
    }
    return data;
  }
}
- Other options are loading all data you really need in a @PostConstruct
- You have to take care about scope, reseting the data, Serializable, etc.
- And you should only "update" the blocks you want to reload, when you click a link. the 'update=":contentFrm:contentFrame"' looks like you're updating everything.

All this has nothing to do with PrimeFaces and is basic JSF application design.

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: jossey and 21 guests