JPA EclipseLink 2 производительность запросов - PullRequest
2 голосов
/ 04 февраля 2011

ПРИМЕНЕНИЕ и ОКРУЖАЮЩАЯ СРЕДА

Корпоративное приложение Java EE / JSF2.0 / JPA, которое содержит веб-модуль и модуль EJB. Я создаю PDF-документы, которые содержат оценочные данные, запрошенные через JPA.

Я использую MySQL в качестве базы данных, с движком MyISAM для всех таблиц. JPA-провайдер - EclipseLink с кэшем, установленным на ALL. FetchType.EAGER используется в отношениях.

ПОСЛЕ РАБОТЫ ПРОФИЛЯТОР NETBEANS

Результаты Profiler показывают, что следующий метод вызывается чаще всего. В этом сеансе было 3858 вызовов с ~ 80 секундами от запроса до ответа. Это занимает 80% процессорного времени. В таблице Question 680 записей.

public Question getQuestionByAzon(String azon) {
    try {
        return (Question) em.createQuery("SELECT q FROM Question q WHERE q.azonosito=:a").setParameter("a", azon).getSingleResult();
    } catch (NoResultException e) {
        return null;
    }
}

Сущность Question:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Question implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(unique = true)
    private String azonosito;
    @Column(nullable = false)
    @Basic(optional = false)
    private String label;
    @Lob
    @Column(columnDefinition = "TEXT")
    private String help;
    private int quizNumber;
    private String type;
    @ManyToOne
    private Category parentQuestion;

    ...

    //getters and setters, equals() and hashCode() function implementations

}

Есть четыре сущности, расширяющие Question.

Столбец azonosito должен использоваться в качестве первичного ключа, но я не вижу в этом основной причины низкой производительности.

Меня интересуют предложения по оптимизации. Не стесняйтесь спрашивать, если вам нужна дополнительная информация!

РЕДАКТИРОВАТЬ Смотрите мой ответ, суммируя лучшие результаты

Заранее спасибо!

Ответы [ 4 ]

3 голосов
/ 07 февраля 2011

Использование LAZY - хорошее начало, я бы порекомендовал вам всегда делать все LAZY, если вас вообще беспокоит производительность.

Также убедитесь, что вы используете ткачество (агент Java SE, или Java EE / Spring, или статический), поскольку LAZY OneToOne и ManyToOne зависят от этого.

Было бы неплохо изменить Id на другое поле, если вы всегда запрашиваете его, и оно уникально. Вам также следует проверить, почему ваше приложение продолжает выполнять один и тот же запрос снова и снова.

Вы должны сделать запрос NameDQuery не использовать динамический запрос. В EclipseLink вы также можете включить кеш запроса для запроса (если он является именованным запросом), это позволит включать обращения к кешу в результате запроса.

1 голос
/ 05 февраля 2011

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

1 голос
/ 04 февраля 2011

У вас есть уникальный индекс для столбца azonosito в вашей базе данных. Может быть, это поможет. Я бы также предложил выбрать только те поля, которые вам действительно нужны, поэтому, возможно, некоторые из них могут быть ленивыми, то есть категорией.

0 голосов
/ 12 февраля 2011

В этом ответе я кратко изложу, какое решение было наилучшим для этого конкретного запроса.

Прежде всего, я установил столбец azonosito в качестве первичного ключа и соответственно изменил свои сущности. Это необходимо, поскольку кеш объекта EclipseLink работает с em.find:

public Question getQuestionByAzon(String azon) {
    try {
        return em.find(Question.class, azon);
    } catch (NoResultException e) {
        return null;
    }
}

Теперь, вместо использования QUERY_RESULT_CACHE на @NamedQuery, я настроил объект Question следующим образом:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Cache(size=1000, type=CacheType.FULL)
public abstract class Question implements Serializable { ... }

Это означает, что кеш объектов максимального размера 1000 будет поддерживаться всеми Question сущностями.

Результаты профилировщика ~ 16000 вызовов

QUERY_RESULT_CACHE: ~ 28000 мс

@Cache(size=1000, type=CacheType.FULL): ~ 7500 мс

Конечно, время выполнения становится короче после первого выполнения.

...