我正在开发一个处理繁重数据集的项目。我正在使用 Primefaces 4& 5 ,春天和冬眠。我必须显示一个非常庞大的数据集,如min 3000行,100列,各种功能,如排序,过滤,行扩展等。我的问题是,我的应用程序需要8到10分钟来显示整个页面以及其他功能(排序,过滤)也需要很多时间。我的客户根本不开心。但是,我可以使用分页,但我的客户端不再需要分页。所以我决定使用livescroll,但遗憾的是我没有实现 livescroll with lazyload或没有lazyload ,因为PF中有关于livescroll的错误。我之前发布过这个问题here ,但没有找到解决方案。
这个性能问题非常关键,对我来说是个不错的选择。要显示包含100列的3000行,加载的页面大小约为10MB。 我已经计算了JSF的各种生命周期所消耗的时间,使用 Phase-listener 我发现其浏览器正在花时间解析jsf呈现的响应。为了完成所有阶段,我的申请仅用了25秒。 最小化我想提高我的项目的性能。请分享任何有助于克服此问题的想法,建议和任何事情
注意:getter和setter中没有数据库操作,也没有复杂的业务逻辑。
更新: 这是我没有lazyload的数据表:
<p:dataTable
style="width:100%"
id="cdTable"
selection="#{controller.selectedArray}"
resizableColumns="true"
draggableColumns="true"
var="cd"
value="#{controller.cdDataModel}"
editable="true"
editMode="cell"
selectionMode="multiple"
rowSelectMode="add"
scrollable="true"
scrollHeight="650"
rowKey="#{cd.id}"
rowIndexVar="rowIndex"
styleClass="screenScrollStyle"
liveScroll="true"
scrollRows="50"
filterEvent="enter"
widgetVar="dt4"
>
这里除了过滤外,一切正常。一旦我过滤,则显示第一页但无法对数据表进行排序或实时滚动。请注意,我已经在 Primefaces5 进行了测试。
第二个Approch
使用具有相同数据表的lazyload 1)当我添加 rows =&#34; 100&#34; livescroll发生但行编辑,行扩展但过滤器&amp;分拣工程。 2)当我删除行时,livescroll适用于行编辑,行扩展等,但过滤器&amp;排序不工作。
我的LazyLoadModel如下
public class MyDataModel extends LazyDataModel<YData>
{
@Override
public List<YData> load(int first, int pageSize,
List<SortMeta> multiSortMeta, Map<String, Object> filters) {
System.out.println("multisort wala load");
return super.load(first, pageSize, multiSortMeta, filters);
}
/**
*
*/
private static final long serialVersionUID = 1L;
private List<YData> datasource;
public YieldRecBondDataModel() {
}
public YieldRecBondDataModel(List<YData> datasource) {
this.datasource = datasource;
}
@Override
public YData getRowData(String rowKey) {
// In a real app, a more efficient way like a query by rowKey should be
// implemented to deal with huge data
// List<YData> yList = (List<YData>) getWrappedData();
for (YData y : datasource)
{
System.out.println("datasource :"+datasource.size());
if(y.getId()!=null)
{
if (y.getId()==(new Long(rowKey)))
{
return y;
}
}
}
return null;
}
@Override
public Object getRowKey(YData y) {
return y.getId();
}
@Override
public void setRowIndex(int rowIndex) {
/*
* The following is in ancestor (LazyDataModel):
* this.rowIndex = rowIndex == -1 ? rowIndex : (rowIndex % pageSize);
*/
if (rowIndex == -1 || getPageSize() == 0) {
super.setRowIndex(-1);
}
else
super.setRowIndex(rowIndex % getPageSize());
}
@Override
public List<YData> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
List<YData> data = new ArrayList<YData>();
System.out.println("sort order : "+sortOrder);
//filter
for(YData yInfo : datasource) {
boolean match = true;
for(Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {
try {
String filterProperty = it.next();
String filterValue = String.valueOf(filters.get(filterProperty));
Field yField = yInfo.getClass().getDeclaredField(filterProperty);
yField.setAccessible(true);
String fieldValue = String.valueOf(yField.get(yInfo));
if(filterValue == null || fieldValue.startsWith(filterValue)) {
match = true;
}
else {
match = false;
break;
}
} catch(Exception e) {
e.printStackTrace();
match = false;
}
}
if(match) {
data.add(yInfo);
}
}
//sort
if(sortField != null) {
Collections.sort(data, new LazySorter(sortField, sortOrder));
}
int dataSize = data.size();
this.setRowCount(dataSize);
//paginate
if(dataSize > pageSize) {
try {
List<YData> subList = data.subList(first, first + pageSize);
return subList;
}
catch(IndexOutOfBoundsException e) {
return data.subList(first, first + (dataSize % pageSize));
}
}
else
return data;
}
@Override
public int getRowCount() {
// TODO Auto-generated method stub
return super.getRowCount();
}
}
我对这些问题逐渐消失,并成为我的噱头。即使我尝试了Primefaces 5
答案 0 :(得分:0)
如果您的数据是从db加载的,我建议你做一个更好的LazyDataModel,如:
public class ElementiLazyDataModel extends LazyDataModel<T> implements Serializable {
private Service<T> abstractFacade;
public ElementiLazyDataModel(Service<T> abstractFacade) {
this.abstractFacade = abstractFacade;
}
public Service<T> getAbstractFacade() {
return abstractFacade;
}
public void setAbstractFacade(Service<T> abstractFacade) {
this.abstractFacade = abstractFacade;
}
@Override
public List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
PaginatedResult<T> pr = abstractFacade.findRange(new int[]{first, first + pageSize}, sortField, sortOrder, filters);
setRowCount(new Long(pr.getTotalItems()).intValue());
return pr.getItems();
}
}
该服务是在使用此模型的ManagedBean中注入的某种后端通信(如EJB)。
分页服务可能是这样的:
@Override
public PaginatedResult<T> findRange(int[] range, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
final Query query = getEntityManager().createQuery("select x from " + entityClass.getSimpleName() + " x")
.setFirstResult(range[0]).setMaxResults(range[1] - range[0] + 1);
// Add filter sort etc.
final Query queryCount = getEntityManager().createQuery("select count(x) from " + entityClass.getSimpleName() + " x");
// Add filter sort etc.
Long rowCount = (Long) queryCount.getSingleResult();
List<T> resultList = query.getResultList();
return new PaginatedResult<T>(resultList, rowCount);
}
请注意,您必须执行分页查询(使用jpa这样的orm为您执行查询,但如果您不使用orm进行分页查询, for oracle查看TOP- N查询,例如:http://oracle-base.com/articles/misc/top-n-queries.php )
请记住,您的返回obj必须也包含总记录作为快速计数:
public class PaginatedResult<T> implements Serializable {
private List<T> items;
private long totalItems;
public PaginatedResult() {
}
public PaginatedResult(List<T> items, long totalItems) {
this.items = items;
this.totalItems = totalItems;
}
public List<T> getItems() {
return items;
}
public void setItems(List<T> items) {
this.items = items;
}
public long getTotalItems() {
return totalItems;
}
public void setTotalItems(long totalItems) {
this.totalItems = totalItems;
}
}
如果您的数据库表设置正确,请注意可能的查询的执行计划并添加正确的索引,这一切都很有用。
希望提供一些改善你表现的提示
最后,记住你的最终用户,人眼不能同时看到更多10-20条记录,所以在一页中有千条记录是没用的。
答案 1 :(得分:0)
您使用了Primefaces展示中使用的默认加载实现。对于从数据库加载数据的情况,这不是正确的实现。
load方法应该使用正确的查询,并考虑:
1)使用的过滤器字段,例如:
String query = "select e from Entity e where lower(e.f1) like lower('" + filters.get(key) + "'%) and..., etc. for the other fields
2)使用的排序列,例如:
query.append("order by ").append(sortField).append(" ").append(SortOrder.ASCENDING.name() ? "" : sortOrder.substring(0, 4)),..., etc. for the other columns.
3)您的查询的总计数1)附加到它。例如:
Long totalCount = (Long) entityManager.createQuery("select count(*) from Entity e where lower(e.f1) like lower('filterKey1%') and lower(e.f2) like lower('filterKey2%') ...").getSingleResult();