Русский English Тэги View Sergey Zolotaryov's profile on LinkedIn Вход
Сравнение JSTL + JDBC с JSF + JPA
Постоянная ссылка 06-07-2007 anydoby java

Понимаю, что сравнивать производительность "низкоуровневых" технологий с "высокоуровневыми" немного несправедливо, но все-таки рискну.

Перед нашей командой стояла задача сделать страницу, на которой одновременно можно было бы увидеть до 10000 строк результатов из базы. На все наши доводы, что, мол, мы сделаем пейджинг, или фильтрацию по самым важным записям, кастомер сказал, что ему удобнее видеть все записи одновременно. Ну ладно, сказали мы, будем делать. И вот, что из этого получилось.

Решили задачу сначала в лоб. Мы используем JPA и JSF. Под Weblogic 10 JPA имплементация Kodo (или OpenJPA). Страница, на которой предстояло отображать результаты, состояла из бооольшой таблицы из 5-6 колонок, данные брались из двух таблиц базы через join. Причем хитрый JPA предлагает для ассоциаций тип выборки - EAGER и LAZY. LAZY нам, естественно, не подходил, так как данные нам нужны были все и сразу. А вот EAGER на поверку оказался обычным селектом. То есть после одного селекта, который выбирает 10000 записей, мы имеем еще 10000 запросов для выборки всех наследников. Это мне в JPA очень не понравилось, к примеру, в Hibernate есть тип JOIN для выборки потомка, который позволяет фреймворку сконструировать один запрос для выборки наследников.

Табличка рисуется JSF , сортировку сделали руками, потому что встроенная в компонент по перформансу совсем не годится. В общем, сложили, замерили JMeter'ом - система выдерживает 30 запросов в минуту. При увеличении числа пользователей до 3-х падает в OutOfMemory. И не мудрено :) горы ненужных объектов как на persistence уровне, так и при построении view. В общем кастомер удивился и говорит "оптимизировать быб". Взялись профайлить, думали, что это JPA лажает. А конкретно подозревали, что виновато количество запросов к базе. Переписал запрос на нативный с явным join и замапил результат при помощи @SqlResultSetMapping. Очень удобно, что JPA можно пользовать не только как ORM, но и result set mapper, наподобие iBATIS (хотя, конечно, свободы у iBATIS побольше). Снова померяли, разницы почти никакой. Чистый прирост в persistence уровне составил примерно 15%. Начали копать JSF и оказалось, что он как раз и съедает основную часть CPU и памяти. Было принятно решение внутри JSF страницы всунуть iframe, внутрь которого будет подгружаться страница с результатами выборки, причем результаты формирует JSP страница. Выборка делается чистым JDBC. Контроллер сервлет обрабатывает входные параметры - поле сортировки, параметры фильтров и тд., делает запрос и кладет в request scope итератор, который бегает вперед по resultset'у и выдает запись за записью в виде объекта. Причем объект каждый раз возвращается один и тот же, только перезаполняется каждый раз новыми данными. При помощи этой хитрости удалось избежать длительных задержек на GC. После выборки делается include JSP страницы с представлением (использовали JSTL, чтобы не писать скриптлеты), коннект к базе закрывается как только заканчивается рендеринг. Результаты превзошли самые смелые ожидания. Прирост производительности составил примерно 20 раз! Мы даже не стали замерять, насколько меньше стало уходить памяти - это очевидно. Соглашусь, что увеличилась сложность решения, однако MVC паттерн был соблюден, хоть и немного на более низком уровне. Но, опять же, результат того стоит. После этой операции мы переписали еще один кусок приложения на servlet/jsp/jdbc, остальное оставили как есть, на небольших объемах данных JPA/JSF работают быстро и разработка сложных форм действительно проще. Но когда нужно показать что-то большое и быстро, то приходится опускаться уровнем ниже.

Добавить комментарий

alexander.abakumov
17-07-2007

Ну и еще один "+" для удобства пользования:

Css аттрибут table-layout: fixed позволяет отображать данные в таблице не дожидаясь загрузки всего массива (а он не маленький).

Сделано это так:

alexander.abakumov
17-07-2007

В догонку: штука работает под Internet Explorer (не знаю с какой версии, но современные IE шарят такое).

jeseme
14-12-2008

а чем вам не пронавилось родное jstl решение

jeseme
14-12-2008

движок съел теги :)

а чем вам не пронавилось родное jstl решение sql:query var="q" и потом c:forEach items="${q.rows}" , раз уж и так у вас вьюха сделана на jstl

anydoby
14-12-2008

Да, я знаю, что есть такое. Но проблема была в том, что нам нужно было самое быстрое решение. В том решении, которое мы реализовали, переиспользовался даже DTO объект. Плюс это не есть MVC подход - в JSP тагах очень сильно ограничены возможности обработки ошибок и as a rule of thumb, jstl sql тэги рекомендуется использовать только в тестовых целях.

Предыдущая статья Свой сервер Следующая статья ERROR: invalid console appender config detected, console stream is looping