2010-06-15 2 views
2

Я уверен, что может улучшить производительность следующего FindByName запроса спящего режима:Что такое быстрый запрос findByName с hibernate?

public List<User> findByName(String name) { 
    session.createCriteria(User.class).add(Restrictions.eq("name", name)).list(); 
} 

Узким является то, что метод FindByName и я не могу использовать идентификатор вместо.

В моем случае я знаю, что имя уникально, но добавление аннотации индекса к атрибуту имени не улучшило производительность. Я сделал следующее:

class User { 
    @Index(name = "nameIdx") 
    private String name;  
} 

Каким образом я должен улучшить или даже более важно: в каких путях я должен улучшить его первым? Мне понадобится полный объект со всеми коллекциями (layz или нет) и deps этого класса.

Или я могу улучшить его, если хочу несколько объектов пользователя (и знаю несколько имен)?

Update1:

@Index аннотации не улучшают производительность, так как база данных уже индекс, из-за моей уникальное ограничение аннотации:

@UniqueConstraint(columnNames = {"name"}) 

UPDATE2:

  1. Внимательно прочитайте ответы!

  2. С помощью журнала SQL я увидел, что реальная проблема заключалась в том, что было сделано много предложений по обновлению и вставке, хотя я не совершал транзакций и не выполнял их. Причиной, что было то, что я сделал (в цикле):

    User u = findByName(name); 
    if(u == null) 
        attach(u = new User(name)); 
    

    и так зимуют потребности промывать вновь созданных пользователей к БД перед каждым запросом FindByName. Я решил это с помощью собственного кэша (LinkedHashMap).

  3. Еще одно усовершенствование я сделал через наконечник Jens Шаудера:

    public Collection<User> findByNames(Collection<String> names) { 
        return session.createCriteria(User.class). 
          add(Restrictions.in("name", names)).list(); 
    } 
    
  4. Дальнейшее улучшение может быть сделано при определении некоторых из коллекции пользователя не ленивых:

    Read this answer, чтобы получить даже лучший вариант.

  5. Последнее и самое важное для меня: замена мои детали SortedSet со списком и выполнив следующие действия в методе GetItems:

    Set set = new LinkedHashSet(items); 
    items.clear(); 
    items.addAll(set); 
    Collections.sort(items, itemComparator); 
    return Collections.unmodifiableCollection(items); 
    

    с тем, что, спящий режим может работать по сбору предметов (т.е. добавление) без загрузки всей коллекции из базы данных.

@Pascal Thivent и @Jens Schauder: куча благодарностей!К сожалению, что я могу использовать только один ответ: -/

Полезные настройки Logging:

log4j.logger.org.hibernate.tool.hbm2ddl=INFO, StdoutApp 
log4j.logger.org.hibernate.SQL=INFO, StdoutApp 
# additionally provide the information which parameters will be bound: 
log4j.logger.org.hibernate.type=TRACE 

.

+0

* (...) потому что база данных уже имела индекс из-за моей уникальной аннотации ограничения *: это очень вероятно. Вам действительно нужно проверить план запроса. –

+0

ОК. Очень благодарю всех вас за комментарии! Теперь производительность является разумной. См. Обновленный вопрос. – Karussell

ответ

2

В моем случае я знаю, что имя уникально, но добавление аннотации индекса к атрибуту имени не улучшило производительность. Узким местом является метод findByName.

Я не считаю, что это ... пока не показывают некоторые цифры доказать, что я неправ :) Итак:

  • Дважды проверьте, что индекс генерироваться (проверить заявления DDL и база данных). Для этого запроса вам понадобится индекс в этом столбце.
  • Проверьте план запроса для сгенерированного запроса (должно быть что-то вроде SELECT * FROM USER u WHERE u.NAME = 'foo') и времени выполнения.

Позже вы можете активировать кеш второго уровня и кэшировать запрос. Но база данных - это место для начала (кеширование вещей слишком рано просто скроет настоящую проблему).

И измерьте вещи! Если вы не можете измерить его, вы не сможете его улучшить. --Lord Kelvin.

+0

Возможно, когда таблица будет маленькой, индекс не будет использоваться, хотя это выглядит как идеальное совпадение. И, конечно, вполне возможно, что OP добавил аннотацию, но не изменил схему :) –

+0

Спасибо за ваше предложение! Теперь я проверю, был ли индекс создан ... – Karussell

+0

@Jens Schauder: Как мне изменить схему? (Я запускал drop + create Schema до моего медленного сеанса импорта) – Karussell

3

Вы не обеспечивают достаточной информации для полного ответа, но вот некоторые идеи:

  • вы можете использовать идентификатор вместо этого? Hibernate будет готовить запросы для выбора по id, так что они будут (немного) быстрее, чем другие запросы.
  • - это имя правильно проиндексировано? Для этого запроса он должен иметь уникальный ключ (вы намекаете, вы ожидаете одного результата). Разумеется, такой индекс снижает затраты на вставку, обновление и удаление.
  • Когда мы приходим к ссылкам, это зависит от того, что вы подразумеваете под действием: время, пока утверждение не вернется? Тогда вы должны использовать ленивую загрузку. Это делает первый оператор быстрее и, следовательно, быстрее. Конечно, после этого у вас будет больше заявлений, после того как вы получите обезвоживание. В противном случае (некоторые) нетерпевая загрузка, вероятно, быстрее, хотя это сильно зависит от деталей.
  • использует кэширование, это может помочь особенно для ссылок, если они могут быть извлечены из кеша.
  • настройте свою базу данных. Дайте ему достаточно памяти, чтобы держать все в памяти все время.
  • настроить свою сеть. С небольшими запросами, подобными показанному, задержка может быть проблемой
  • удалите сеть, поставив db на том же компьютере, что и код. Предполагая, что он достаточно большой.

Как вы можете видеть, у вас есть множество вариантов настройки. Единственное, что я ожидал бы хорошего эффекта для усилий, - это рассмотреть индекс. Конечно, это может измениться, когда мы имеем больше информации о проблеме (например, полная структура Таблицы, индексы, спящий режим отображения, размером таблиц ...)


UPDATE на основе комментария:

При настройке , первый вопрос: что нам нужно настроить? Является ли это преобразование критериев в инструкцию SQL? Если это так, то предложение sql напрямую может выполнить эту работу.

Это фактическое выполнение инструкции sql? Если это так, определение выражения sql в результате опубликованного кода будет первым делом.

Я никогда не видел реального случая, когда хранимая процедура делала вещи быстрее. Конечно, это не значит, что таких случаев не существует. Но оптимизаторы современных rdbms довольно умны.

Итак, чтобы это началось правильно: настройте регистрацию, чтобы вы могли видеть каждый SQL-запрос с точной меткой времени. Как и время начала и окончания полного процесса, который вы настраиваете. Если это около сотен казней, вам придется переварить материал.

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

В большинстве случаев заявления sql виновны в плохом исполнении, но не следует делать выводы.


Обновление на многих имен части:

Вы можете использовать InExpression: http://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/criterion/InExpression.html найти несколько объектов в один присест. Это будет быстрее, чем отдельные запросы.

+0

Извините за то, что не предоставил недостаточно информации, это коммерческий проект, и я постараюсь предоставить вам максимальную информацию, не зная моего босса. Во-первых: я не могу использовать идентификатор. Хотя я мог использовать собственные SQL-запросы или хранимую процедуру? Это улучшит производительность? – Karussell

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