2012-03-20 4 views
2

데이터 레코드가 5000 개 이상인 표가 있습니다. 이 데이터는 매일 계속 증가하고 있습니다. 표를 그리는 페이지를로드 할 때 그리드가 한 번에 10 개의 행을 표시해야하는 데이터를 표시하기까지는 거의 1 분이 걸립니다.jqGrid로 지연로드를 구현할 수 있습니까?

이 jqGrid를 사용하여 지연로드를 구현할 수 있습니까?

는 JSON 문자열 생성하는 내 작업입니다 :

@RequestMapping(value = "studentjsondata", method = RequestMethod.GET) 
public @ResponseBody String studentjsondata(HttpServletRequest httpServletRequest) { 
    Format formatter = new SimpleDateFormat("MMMM dd, yyyy"); 
    String column = "id"; 
    if(httpServletRequest.getParameter("sidx") != null){ 
     column = httpServletRequest.getParameter("sidx"); 
    } 
    String orderType = "DESC"; 
    if(httpServletRequest.getParameter("sord") != null){ 
     orderType = httpServletRequest.getParameter("sord").toUpperCase(); 
    } 
    int page = 1; 
    if(Integer.parseInt(httpServletRequest.getParameter("page")) >= 1){ 
     page = Integer.parseInt(httpServletRequest.getParameter("page")); 
    } 
    int limitAmount = 10; 
    int limitStart = limitAmount*page - limitAmount; 
    List<Student> students = Student.findAllStudentsOrderByColumn(column,orderType,limitStart,limitAmount).getResultList(); 
    List<Student> countStudents = Student.findAllStudents(); 
    double tally = Math.ceil(countStudents.size()/10.0d); 
    int totalPages = (int)tally; 
    int records = countStudents.size(); 


    StringBuilder sb = new StringBuilder(); 
    sb.append("{\"page\":\"").append(page).append("\", \"records\":\"").append(records).append("\", \"total\":\"").append(totalPages).append("\", \"rows\":["); 
    boolean first = true; 
    for (Student s: students) { 
     sb.append(first ? "" : ","); 
     if (first) { 
      first = false; 
     } 
     sb.append(String.format("{\"id\":\"%s\", \"cell\":[\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"]}",s.getId(), s.getId(), s.getFirstName(), s.getLastName(), formatter.format(s.getDateOfBirth().getTime()), s.getGender(), s.getMaritalStatus())); 
    } 
    sb.append("]}"); 
    return sb.toString(); 
} 

을 그리고 이것은있는 jqGrid와 페이지입니다 :

$("#studentGrid").jqGrid({ 
      url: '/starburst/programmes/studentjsondata', 
      datatype: 'json', 
      height: 'auto', 
      colNames:['id','First Name', 'Last Name', 'Date Of Birth', 'Gender', 'Marital Status'], 
      colModel:[ 
       {name:'id',index:'id', width:15}, 
       {name:'firstName',index:'firstName', width:30, formoptions:{elmprefix:'(*) '}, editable:true, edittype: 'text', editrules:{required:true}}, 
       {name:'lastName',index:'lastName', width:30, formoptions:{elmprefix:'(*) '}, editable:true, edittype: 'text',editrules:{required:true}}, 
       {name:'dateOfBirth',index:'dateOfBirth', width:30, formoptions:{elmprefix:'(*) '},editrules:{required:true}, editable:true, edittype: 'text',    
        editoptions: { 
         dataInit: function(element) { 
          $(element).datepicker({dateFormat: 'MM dd, yy'}) 
         } 
        } 
       },      
       {name:'gender',index:'gender', width:30, formoptions:{elmprefix:'(*) '}, editable:true, editrules:{required:true}, edittype: 'select', 
        editoptions:{value:{}} 
       }, 
       {name:'maritalStatus',index:'maritalStatus', width:30, formoptions:{elmprefix:'(*) '}, editable:true, editrules:{required:true}, edittype: 'select', 
        editoptions:{value:{}} 
       }      
      ], 
      rowNum:10, 
      autowidth: true, 
      pager: '#pager', 
      sortname: 'id', 
      viewrecords: true, 
      sortorder: "desc", 
      caption:"Students", 
      emptyrecords: "Empty Records", 
      subGrid: true, 
      /* <![CDATA[ */ 
      onSelectRow: function(id){ 
       if((lastsel != 0)&&(id!==lastsel)){ 
        $("#studentGrid").jqGrid('collapseSubGridRow', lastsel);     
       } 
       lastsel=id; 
      }/* ]]> */ 
     }); 
     $("#studentGrid").jqGrid('navGrid', "#pager", {edit:false,add:false,del:false,search:true},{ },{ },{ }, 
     { 
      sopt:['eq', 'ne', 'lt', 'gt', 'cn', 'bw', 'ew'], 
      closeOnEscape: true, 
      multipleSearch: true, 

참조 쿼리 아래 :

public static TypedQuery<tt.edu.sbcs.model.Student> findAllStudentsOrderByColumn(String column, String orderType, int limitStart, int limitAmount) { 
    EntityManager em = Programme.entityManager(); 
    TypedQuery<Student> q = em.createQuery("SELECT o FROM Student AS o ORDER BY"+" "+column+" "+orderType, Student.class); 
    q.setFirstResult(limitStart);//used to skip the first "N" elements form the result set, it indexes results form zero 
    q.setMaxResults(limitAmount); 
    return q; 
} 

제한 금액 나는 위의 행동을 취했다. 이 값은 10입니다.

+1

병목 현상이 발생한 곳을 보려고 했습니까? JS/HTML 렌더링 또는 서블릿 핸들러 코드에서? 메소드에 시간 계산을 추가하고 실행하는 데 걸리는 시간을 인쇄 할 수 있습니다. 적어도 당신은 개선해야 할 부분을 알고있을 것입니다. 내가 본 것으로부터 findAllStudents는 개체를 카운트하는 데 매우 비효율적 인 방법으로 보입니다 (카운트 쿼리는 훨씬 더 효과적입니다). 또한 다음 페이지를 가져올 때 이전 페이지가 아닌 해당 페이지의 객체 만 가져와야합니다 (객체 10부터 20까지만 가져오고 1에서 20까지만 가져 오기) –

+0

방화광을 사용하여 걸리는 시간을 감지합니다 실행 .. 현재 약 46s. 당신이 진술 한대로 객체를 가져 오는 방법을 모르겠습니다. 이것을 달성하는 방법을 조언 해 줄 수 있습니까? – pundit

+0

어떤 기술을 사용하고 있습니까? JDBC를 통한 원시 SQL? JPA? 최대 절전 모드? 다른 것? 그것은 또한 DB의 유형에 의존합니다 : MySQL, PostgresQL, Oracle, H2, HSQL, 등등 ...? Firebug는 좋은 도구이지만 Java 메소드의 실행 시간을 측정하려 했습니까? 최적화하고 싶다면 병목 현상을 실제로 최적화해야하므로 먼저 Java 코드에 문제가 있는지 확인해야합니다. 메소드의 처음과 끝 사이의'System.currentTimeInMillis()'사이의 간단한 차이는 그것을해야한다. –

답변

2

OK, JPA를 기반으로 한 부분적인 대답입니다. (그러나 나는 그것을 Hibernate에 적용하는 것이 거의 중요하지 않을 것입니다). 당신은 필요한 객체를 가져 오기 위해 같은 것을 할 수 있어야한다 : 카운트를 들어

Query query = em.createQuery("select o from " + "Student"+ " as o order by o.id"); 
query.setFirstResult(start); 
query.setMaxResults(end - start); 
return query.getResultList(); 

는이 같은 뭔가를해야한다 : 나는 더 많은 정보가있을 때

Number count = (Number) em.createQuery("select count(id) from " + "Student").getSingleResult(); 
if (count == null) { 
    count = Integer.valueOf(0); 
} 
return count.intValue(); 

편집됩니다.

+0

나는 위 질문을 편집했다. 검토하시기 바랍니다. 자바 코드를 실행하는 데 걸린 시간도 36 초라는 점에 유의하십시오. – pundit

3

우선 1 분 안에 총 5000 개에서 10 개로딩하는 것이 매우 느림입니다. 나는 서버 코드와 jqGrid가 병목 현상이 아니라고 생각한다.

코드의 첫 번째 매우 의심 행은 학생의 를 얻을 필요가

List<Student> countStudents = Student.findAllStudents(); 

이지만, 당신이 얻을 것으로 보인다하고 사용하는 모든 학생들의 모든 속성 다음 두 줄에 countStudents.size(). 최대 무엇을 수행해야하는 대신에 당신이 SELECT * FROM dbo.Students을 meens이의

SELECT COUNT(*) FROM dbo.Students 

같은 것입니다.

데이터베이스에 심각한 문제가 있거나 findAllStudentsOrderByColumn 코드 구현에 1 분이 걸릴 경우 심각한 문제가 발생할 수 있습니다. 아마도 엔티티 모델 또는 데이터베이스 모델을 나타내는 클래스가있을 것입니다. 성능이 매우 나빠진다면 데이터베이스 액세스를 매우 신중하게하는 코드를 검사하거나 데이터베이스 쿼리를 직접 지정할 수있는 데이터베이스에 대한 좀 더 직접적인 액세스를 고려해야합니다. 저는 Java 나 Spring 개발자는 아니지만, 분명히 말할 수 있습니다. 5000 행의 10 행 요청이 1 초보다 많으면 더 느립니다.

id을 포함하여 하나의 테이블에서 일부 열을 반환해야하는 것처럼 보입니다.그래서 당신은 다음의 모든 페이지에 대한 다음과 같은

WITH GetAll (id, firstName, lastName, dateOfBirth, gender, maritalStatus) AS (
    SELECT id, firstName, lastName, dateOfBirth, gender, maritalStatus 
    FROM dbo.Students 
    ORDER BY id 
), GetTop (id, firstName, lastName, dateOfBirth, gender, maritalStatus) AS (
    SELECT TOP(20) * FROM GetAll -- skip 2 pages per 10 rows 
), GetNext (id, firstName, lastName, dateOfBirth, gender, maritalStatus) AS (
    SELECT TOP(10) a.* FROM GetAll AS a 
     LEFT OUTER JOIN GetTop AS t ON t.id = a.id 
    WHERE t.id IS NULL 
) 
SELECT * FROM GetNext 

처럼 첫 번째 데이터의 페이지 뭔가를 얻을 수 SELECT

같은
SELECT TOP(10) id, firstName, lastName, dateOfBirth, gender, maritalStatus 
FROM dbo.Students 
ORDER BY id 

으로 데이터를 얻을 수 있습니다. common table expression (CTE) 구문을 사용했지만 데이터베이스가 지원하지 않으면 하위 쿼리를 사용할 수 있습니다.

모든 열을 기준으로 정렬 할 수 있으므로 테이블의 모든 열에 INDEXes를 만들어 정렬 성능을 향상시켜야합니다. (필자는 Students 테이블이 초당 많은 변경으로 수정되지 않을 것이므로 인덱스는 테이블의 성능을 저하시키지 않을 것이라고 생각합니다.)

또 다른 고려 사항은 직렬화를 JSON으로 변경하는 것입니다. String.format("\"%s\", someString)의 사용은 위험합니다. \ 문자로 이스케이프해야하는 문자가 있습니다. 나는 "\을 의미합니다. 코드를 안전하게 만들려면이 작업을 수행해야합니다. 일반적인 방법은 직렬화를 위해 사용하는 언어로 존재하는 표준 클래스를 사용하는 것입니다 (예 : here 또는 here 참조).

다음 팁은 '당신은 두 번 id 값을 보내지 않는 것'과 '돈 것

{"id":"%s", "cell":["%s", "%s", "%s", "%s", "%s", "%s"]} 

["%s", "%s", "%s", "%s", "%s", "%s"] 

대신 형태로 행의 데이터를 jsonReader: {cell: ""}를 사용하고 반환하는 것입니다 문자열 "id" "cell"과 다른 불필요한 문자 ('{', ':', ...)를 보내십시오.

클라이언트 측에서는 항상을 사용하십시오. gridview: true jqGrid 옵션을 사용하십시오. jqGrid가 매우 빨리 수행되기 때문에 10 행의 데이터를 사용하면 심각한 차이가 나타나지 않지만 더 많은 행을 사용하면 차이가 명확 해집니다.

마지막 제안 : formatter: 'date'을 사용하고 과 같은 ISO 8601 형식의 날짜를 보내야합니다.

관련 문제