2012-03-20 3 views
2

У меня есть сетка с более чем 5000 записей данных. Эти данные постоянно растут. Когда я загружаю страницу с помощью сетки, она занимает почти минуту, пока сетка не покажет данные, которые я должен отображать 10 строк за раз.Можно ли выполнить ленивую загрузку с помощью 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; 
} 

Предел суммы i в приведенном выше действии. это значение равно 10.

+1

Вы пытались увидеть, где узкое место? в рендеринге JS/HTML или в коде обработчика сервлета? Вы уже можете добавить некоторое время в свой метод и распечатать время, необходимое для его выполнения. По крайней мере, вы бы знали, где вам нужно улучшить. Из того, что я вижу, findAllStudents выглядит очень неэффективным способом подсчета объектов (счет-запрос должен быть намного более эффективным). Кроме того, когда вы выбираете следующую страницу, вам нужно только извлекать объекты этой страницы, а не предыдущие (только для получения объектов с 10 по 20, а не с 1 по 20). –

+0

Я использую firebug для определения времени, которое потребовалось выполнить .. в настоящее время его около 46s. Я не уверен, как получить объекты, как вы заявили. вы могли бы посоветовать, как это сделать? – pundit

+0

Какая технология вы используете? Сырой SQL через JDBC? JPA? Hibernate? Что-то другое? Это также зависит от типа БД: MySQL, PostgresQL, Oracle, H2, HSQL и т. Д. ...? Firebug - хороший инструмент, но вы пытались измерить время выполнения вашего Java-метода? Когда вы хотите оптимизировать, вам нужно убедиться, что вы фактически оптимизируете узкое место, и, следовательно, вы должны сначала убедиться, что проблема действительно в вашем Java-коде. Простое различие между 'System.currentTimeInMillis()' между началом и концом метода должно это сделать. –

ответ

2

ОК, так что это частичный ответ на основе 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

Я редактировал вопрос выше. Пожалуйста ознакомтесь. Обратите внимание, что время для запуска java-кода - 36 секунд. – pundit

3

Прежде всего, я обнаружил, что загрузка 10 рядов из 5000 всего за 1 минуту составляет ВНЕШНИЙ медленный. Я думаю, что код сервера, а не jqGrid в узком месте в вашем случае.

Первый очень подозревала строка вашего кода

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

Вы должны получить только число студентов, но мне кажется, что вы получите все свойства всех студентов, а затем использовать countStudents.size() в двух следующих строках. Максимум, что нужно сделать, это что-то вроде

SELECT COUNT(*) FROM dbo.Students 

Вместо этого Меенса вы SELECT * FROM dbo.Students.

Возможно, у вас есть серьезные проблемы в базе данных или в реализации функции findAllStudentsOrderByColumn, если ваш код занимает 1 минуту. Вероятно, у вас есть несколько классов, которые представляют модель сущности или модель базы данных. Если вы получаете такую ​​плохую производительность, вам нужно тщательно изучить код, который делает доступ к базе данных, или рассмотреть возможность использования более прямого доступа к базе данных, где вы можете напрямую указать запросы к базе данных. Я не разработчик Java или Spring, но могу окончательно сказать, что если запрос из 10 строк из 5000 получает больше 1 секунду, то это уже слишком медленно.

Похоже, что вам нужно вернуть несколько столбцов из одной таблицы, включая id.Таким образом, вы можете получить данные с SELECT как

SELECT TOP(10) id, firstName, lastName, dateOfBirth, gender, maritalStatus 
FROM dbo.Students 
ORDER BY 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 

для всех последующих страниц. Я использовал common table expression (CTE) синтаксис, но вы можете использовать подзапросы, если ваша база данных не поддерживает его.

Поскольку вы разрешаете сортировать по каждому столбцу, вы должны создавать ИНДЕКСЫ в каждом столбце таблицы, чтобы улучшить производительность сортировки. (Я думаю, что таблица «Студенты» не будет изменена с большим количеством изменений в секунду, поэтому индексы не уменьшат производительность таблицы).

Еще одна вещь, которую вы должны рассмотреть - это изменить сериализацию на JSON. Использование String.format("\"%s\", someString) опасно. Есть некоторые символы, которые должны быть экранированы с символом \. Я имею в виду " и \. Вы должны сделать это, чтобы сделать код безопасным. Обычная практика заключается в использовании некоторых стандартных классов, существующих на вашем языке для сериализации (см., Например, here или here).

Следующий совет заключается в использовании jsonReader: {cell: ""} и возвращать данные для строки в виде

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

вместо

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

Вы не отправлять id значения в два раза и не» t посылает строки "id" "cell" и некоторые другие ненужные символы ('{', ':', ...).

На стороне клиента вы должны всегда использовать gridview: true jqGrid вариант. С 10 строками данных вы не увидите серьезных отличий, потому что jqGrid будет очень быстро, но с большим количеством строк разница будет очень ясной.

Последнее предложение: вы должны использовать formatter: 'date' и отправить дату в формате ISO 8601: 2012-03-20.

Смежные вопросы