Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Медленность HIBERNATE, Медленно работает запрос. 
:(
    Опции темы
h4ck3r
Дата 9.11.2009, 15:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Здравствуйте. Делаю небольшую программку с использованием hibernate (программа для подсчета очков в ТЕННИС).
Сначала коротоко о программе: 
имеется 3 таблицы в БД: ТУРНИРЫ (айди, дата_турнира, название),  УЧАСТНИКИ (айди, код_турнира,код_участника,количество_очков,место), и собственно таблица ИГРОКИ (айди, имя,фамилия,рейтинг и тд).

Проблема в следующем:
Нужно сделать относительно сложную табличку, в которой столбцами будут все турниры, которые были сыграны, а в строку соответственно всех игроков и количества очков по каждому турниру.


реализовал таким образом:
Проблема в том что при нажатии на соответсвующий пункт меню где-то секунд 20 все висит и потом только табличка появляется.
Я реализовал тоже самое стандартным методом работой с базой (такой же запрос, только с использование sql) и табличка появляется секунды через 3.
Я думаю что не может же хибер настолько "тормозить".Проблемы скорее всего в каких-то настройках или может еще в чем ? Подскажите, кто чем может =)
 
Код

public class PanelRank extends javax.swing.JPanel {
private TournamentsDAO tournamentsDAO=null;
private ParticipantsDAO participantsDAO=null;
private PlayersDAO playersDAO=null;
private String[] StringRank=null;
private   List<Tournaments> TournamentsList=null;
private List <Participants> par=null;

    /** Creates new form PanelRank */
    public PanelRank(Factory factory,String sex) {
        initComponents();
        this.tournamentsDAO=factory.getInstance().getTournamentsDAO();
        this.participantsDAO=factory.getInstance().getParticipantsDAO();
        this.playersDAO=factory.getInstance().getPlayersDAO();        
        StringRank= CreateTableRow(sex);
        TableRank.setModel(new javax.swing.table.DefaultTableModel(CreateObj(sex),StringRank));
        
    }

// создание как раз столбцов с небольшой инфой по игроку и всеми турнирами

private String[] CreateTableRow(String type)
    {
    TournamentsList=tournamentsDAO.getTournamentsByType(type);
        String[] s=new String[TournamentsList.size()+5];
        s[0]="№";
        s[1]="ФИО";
        s[2]="Г/Р";
        s[3]="К";
        for (int i = 4; i < s.length-1; i++) {
        s[i]=TournamentsList.get(i-4).getName();
            }
        s[s.length-1]="Рейтинг";
     return s;
    }


 private Object[][] CreateObj(String sex){
   
     List <Players> playersList=playersDAO.getPlayersBySex(sex,"Rank desc");  
     Object[][] obj=new Object[playersList.size()][StringRank.length];
     for (int i = 0; i < obj.length; i++) {
         obj[i][0]=(i+1);
         obj[i][1]=playersList.get(i).getSurname()+" "+playersList.get(i).getName();
         obj[i][2]=playersList.get(i).getBirthday()+"";
         obj[i][3]=playersList.get(i).getKoeficient()+"";
         obj[i][StringRank.length-1]=playersList.get(i).getRank()+"";

         for (int j = 4; j < StringRank.length-1; j++) {
         obj[i][j]=participantsDAO.getParticipantsPoints(playersList.get(i),TournamentsList.get(j-4));    //вот эта строчка заставляет отрисовывать таблицу порядка 20 секунд. (У меня около 100 игроков и около 2000 записей в таблице УЧАСТНИКИ)
     }
         
 }  
     return obj;
 }



ВОТ как реализован этот "тормозящий" запрос:

public String getParticipantsPoints(Players pl, Tournaments t) {
    Session session = null;
    List list = new ArrayList<Participants>();
    String rezult="0";
    try {

      session = HibernateUtil.getSessionFactory().openSession();
      list = session.createQuery("from Participants where key_player = "+pl.getKeyPlayer()+" and key_tournament="+t.getKeyTournament()).list();
      if (!list.isEmpty()){
         List<Participants> l=list;
         rezult=l.get(0).getPoints()+"";
      }
    } catch (Exception e) {
      JOptionPane.showMessageDialog(null, e.getMessage(), "' Ошибка getParticipantsByPlayer'", JOptionPane.OK_OPTION);
    } finally {
      if (session != null && session.isOpen()) {
        session.close();
      }
    }
    return rezult;
    }




PM MAIL   Вверх
ivanovpv
Дата 9.11.2009, 15:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Варвар
**


Профиль
Группа: Участник
Сообщений: 639
Регистрация: 26.1.2005
Где: Москва

Репутация: 4
Всего: 28



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


--------------------
Aut viam inveniam aut faciam
PM MAIL Skype   Вверх
h4ck3r
Дата 9.11.2009, 16:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Цитата(ivanovpv @  9.11.2009,  15:51 Найти цитируемый пост)
Если записей много, то время может уходить на их передачу по сети.

Может я Вас неправильно понял, но запрос  : 
"session.createQuery("from Participants where key_player = "+pl.getKeyPlayer()+" and key_tournament="+t.getKeyTournament()).list(); " может возвращать либо 1 строчку, либо ниодной..
Как бы так объяснить: имеется грубо говоря 100 строк (игроки) и 20 столбцов (турниры) и вот оно идет построчно по игрокам и ищет для конкретного игрока количество очков в конкретном турнире и так для всех.. То есть пока оно в цикле так обойдет по скажем 20 турниров для сотни игроков проходит как раз вот эти секунд 20 ожидания....Но таким же методом построенный запрос не через хибер делает это гораздо быстрее (секунды 3 и готово.) Еще у меня стоит у этой таблицы Lazy=false для двух других таблиц. т.е. возможно оно с собой еще какието данные подсасывает..Пробовал отключать - ничего не изменилось.Ну во всяком случае незначительно..
Просто не верится,что такая разительная разница во времени может быть..Наверняка что-то у меня неправильно или нерационально =(


PM MAIL   Вверх
ivanovpv
Дата 9.11.2009, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Варвар
**


Профиль
Группа: Участник
Сообщений: 639
Регистрация: 26.1.2005
Где: Москва

Репутация: 4
Всего: 28



Цитата(h4ck3r @  9.11.2009,  16:05 Найти цитируемый пост)
Как бы так объяснить: имеется грубо говоря 100 строк (игроки) и 20 столбцов (турниры) и вот оно идет построчно по игрокам и ищет для конкретного игрока количество очков в конкретном турнире и так для всех.. То есть пока оно в цикле так обойдет по скажем 20 турниров для сотни игроков проходит как раз вот эти секунд 20 ожидания...


Значит дело не Hibernate, а в том, что каждый раз вы подсовываете SQL серверу новый запрос с новыми данными и сервер каждый раз тратит время на парсирование/компиляцию по сути одного и того же запроса. Надо использовать PreparedStatement, чтобы сервер один раз скомпилировал запрос и потом подсовывал изменяемые данные. В идеологии Hibernate/HQL это выглядит примерно так:

Код

int userId = 5;
String sql = "select * from your_table as yt where user_id = :user_id";
SQLQuery query = session.createSQLQuery(sql);
query.setInteger("user_id", userId);
List<?> yourStuff = query.list();



--------------------
Aut viam inveniam aut faciam
PM MAIL Skype   Вверх
LSD
Дата 9.11.2009, 20:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



1. Конфигурируем Hibernate Log4j Appender на показ всех SQL запросов и их параметров.
2. Берем выполненные SQL запросы и пробуем их выполнить из клиента и смотрим на время выполнения и количество возвращаемых данных.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
h4ck3r
  Дата 9.11.2009, 23:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Цитата(LSD @  9.11.2009,  20:51 Найти цитируемый пост)
1. Конфигурируем Hibernate Log4j Appender на показ всех SQL запросов и их параметров.2. Берем выполненные SQL запросы и пробуем их выполнить из клиента и смотрим на время выполнения и количество возвращаемых данных.

Я пишу в нетбинсе, там в настройках стоит вывод запросов всех..Так вот, выводит именно то что нужно:


Код


Hibernate: select participan....where key_player=1 and key tournament=1
Hibernate: select participan....where key_player=1 and key tournament=2
Hibernate: select participan....where key_player=1 and key tournament=3
Hibernate: select participan....where key_player=1 and key tournament=4
Hibernate: select participan....where key_player=1 and key tournament=5
........................................................................................................................
Hibernate: select participan....where key_player=2 and key tournament=1
Hibernate: select participan....where key_player=2 and key tournament=2
Hibernate: select participan....where key_player=2 and key tournament=3
Hibernate: select participan....where key_player=2 and key tournament=4
Hibernate: select participan....where key_player=2 and key tournament=5
........................................................................................................................

и так далее и тому подобное
То есть идут только нужные запросы, но их очень много. И все они абсолютно однотипные..


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

Код

public Object[][] getParticipantsPoints(List<Players> p, List<Tournaments> t) {
    Object[][] obj=new Object[p.size()][t.size()];
    Session session = null;
    List list = new ArrayList<Participants>();
    try { 
      session = HibernateUtil.getSessionFactory().openSession();
        for (int i = 0; i < obj.length; i++) {
            for (int j = 0; j < obj[0].length; j++) {
      list = session.createQuery("from Participants where key_player="+p.get(i).getKeyPlayer()+" and key_tournament ="+t.get(j).getKeyTournament()+"").list();
             if (!list.isEmpty()){
        List<Participants> l=list;
        obj[i][j]=l.get(0).getPoints()+"";
      }
             else obj[i][j]="0";
            }

        }               
    } catch (Exception e) {
      JOptionPane.showMessageDialog(null, e.getMessage(), "' Ошибка getParticipantsByTournaments'", JOptionPane.OK_OPTION);
    } finally {
      if (session != null && session.isOpen()) {
        session.close();
      }
    }
    return obj;
    }

}


Но к сожалению, результат примерно тот же :(

Что же не так ? Как эффективно обработать эту кучу одинаковых запросов ?

PM MAIL   Вверх
fixxer
Дата 9.11.2009, 23:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 672
Регистрация: 14.9.2006
Где: Саратов, Россия

Репутация: 6
Всего: 27



bound parameters? "where keyplayer = ?"


--------------------
user posted image
PM MAIL ICQ   Вверх
h4ck3r
Дата 9.11.2009, 23:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Цитата(fixxer @  9.11.2009,  23:31 Найти цитируемый пост)
bound parameters? "where keyplayer = ?"

А можно поподробнее. Я так понял вы предлагаете заменить
Query("from Participants where key_player = "+pl.getKeyPlayer()+" and key_tournament="+t.getKeyTournament())
на 
Query("from Participants where key_player =? and key_tournament=?")  ?

Что это даст ?

PM MAIL   Вверх
stron
Дата 10.11.2009, 00:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Консультант
***


Профиль
Группа: Комодератор
Сообщений: 1654
Регистрация: 17.7.2003
Где: Питер

Репутация: нет
Всего: 36



Это даст прирос производительности в базе.

С точки зрения базы эти запросы разные:
select participan....where key_player=1 and key tournament=1
select participan....where key_player=1 and key tournament=2

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

А вообще, надо
Код

     for (int i = 0; i < obj.length; i++) {
         obj[i][0]=(i+1);
         obj[i][1]=playersList.get(i).getSurname()+" "+playersList.get(i).getName();
         obj[i][2]=playersList.get(i).getBirthday()+"";
         obj[i][3]=playersList.get(i).getKoeficient()+"";
         obj[i][StringRank.length-1]=playersList.get(i).getRank()+"";
         for (int j = 4; j < StringRank.length-1; j++) {
         obj[i][j]=participantsDAO.getParticipantsPoints(playersList.get(i),TournamentsList.get(j-4));
     }


заменить на что-нибудь более простое

Добавлено через 4 минуты и 19 секунд
+ есть подозрение, что на каждый SQL запрос открывается новый коннект к базе, что является "тяжелой" операцией
одной сессии на все операции должно хватить

Это сообщение отредактировал(а) stron - 10.11.2009, 00:31


--------------------
подписи нет
PM ICQ   Вверх
h4ck3r
Дата 10.11.2009, 00:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Вы знаете, попробовал отойти от хибернейта и сделал что-то как-то постаринке..Получилось вот так вот:
Код

 
public String getParticipantsPoints(String sex, Integer key_player,Integer key_tournament) {
    Session session = null;
    String rez="0";
       
    try {

      session = HibernateUtil.getSessionFactory().openSession();
      String sql="SELECT p.`points` FROM participants p, tournaments t, players pl WHERE p.key_tournament=t.key_tournament AND p.key_player=pl.key_player AND pl.`sex`='"+sex+"' AND t.`key_tournament`='"+key_tournament+"' AND pl.key_player='"+key_player+"'";
       java.sql.Statement st=session.connection().createStatement();
       ResultSet rst=st.executeQuery(sql);       
       rst.next();
       rez=rst.getString(1);
       rst.close();
              
    } catch (Exception e) {
      //JOptionPane.showMessageDialog(null, e.getMessage(), "' Ошибка getParticipantsByPlayer'", JOptionPane.OK_OPTION);
    } finally {
      if (session != null && session.isOpen()) {
        session.close();
      }
    }
    return rez;
    }


Как то не сильно красиво, но разница в работе в таком варианте 2-4 сек, а в вариантах всех что были выше 15-20..
Неплохая разница..Только както выглядит некрасиво , да и метод session.connection() deprecated. Тоже нехорошо.
PM MAIL   Вверх
stron
Дата 10.11.2009, 00:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Консультант
***


Профиль
Группа: Комодератор
Сообщений: 1654
Регистрация: 17.7.2003
Где: Питер

Репутация: нет
Всего: 36



Попробуй как первый шаг использовать связные переменные,
И заменить openSession() на getCurrentSession()

Добавлено через 4 минуты и 41 секунду
Цитата

Query("from Participants where key_player = "+pl.getKeyPlayer()+" and key_tournament="+t.getKeyTournament())
на 
Query("from Participants where key_player =? and key_tournament=?")

лучше на

Код

Query("from Participants where key_player =:keyPlayer and key_tournament=:keyTournament")

через именнованные параметры проще поддерживать будет


--------------------
подписи нет
PM ICQ   Вверх
h4ck3r
Дата 10.11.2009, 00:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Цитата(stron @  10.11.2009,  00:39 Найти цитируемый пост)
через именнованные параметры проще поддерживать будет


Что-то не хотят они почему то работать в таком виде:

Код

 session = HibernateUtil.getSessionFactory().openSession();    
      SQLQuery sql=session.createSQLQuery("SELECT p.`points` FROM participants p, tournaments t, players pl WHERE p.key_tournament=t.key_tournament AND p.key_player=pl.key_player AND pl.`sex`=:sex AND t.`key_tournament`=:key_tournament AND pl.key_player=:key_player");

       sql.setString("sex", sex);
       sql.setInteger("key_tournament", key_tournament);
       sql.setInteger("key_player", key_player);

       java.sql.Statement st=session.connection().createStatement();
       ResultSet rst=st.executeQuery(sql.getQueryString());
       rst.next();
       rez=rst.getString(1);
       rst.close();


 И как правильно будет создать Statement? есть какойто вариант не через "зачеркнутые" методы ?
PM MAIL   Вверх
ivanovpv
Дата 10.11.2009, 09:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Варвар
**


Профиль
Группа: Участник
Сообщений: 639
Регистрация: 26.1.2005
Где: Москва

Репутация: 4
Всего: 28



Цитата(h4ck3r @  10.11.2009,  00:59 Найти цитируемый пост)
И как правильно будет создать Statement? 


Я же говорил уже что надо использовать PreparedStatement

А вообще зря вы от Hibernate отошли. Раз вы сами напрямую лезете в базу - на кой ляд он вам нужен? Тот же PreparedStatement можно реализовать средствами Hibernate (см. выше)


--------------------
Aut viam inveniam aut faciam
PM MAIL Skype   Вверх
h4ck3r
Дата 10.11.2009, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.7.2009

Репутация: нет
Всего: нет





Цитата(ivanovpv @  10.11.2009,  09:32 Найти цитируемый пост)
Я же говорил уже что надо использовать PreparedStatement

В идеологии Hibernate/HQL это выглядит примерно так:
Код

int userId = 5;
String sql = "select * from your_table as yt where user_id = :user_id";
SQLQuery query = session.createSQLQuery(sql);
query.setInteger("user_id", userId);
List<?> yourStuff = query.list();



Если я вас правильно понял , то получилось у меня вот так:

Код

public String getParticipantsPoints3(Players pl, Tournaments t) {
    Session session = null;
    List list = new ArrayList<Participants>();
    String rezult="0";
    try {

      session = HibernateUtil.getSessionFactory().openSession();
      Query query=session.createQuery("from Participants where key_player = :key_player and key_tournament= :key_tournament");
      query.setInteger("key_player",pl.getKeyPlayer());
      query.setInteger("key_tournament",t.getKeyTournament());

      list = query.list();

      if (!list.isEmpty()){
         List<Participants> l=list;
         rezult=l.get(0).getPoints()+"";
      }
    } catch (Exception e) {
      JOptionPane.showMessageDialog(null, e.getMessage(), "' Ошибка getParticipantsByPlayer'", JOptionPane.OK_OPTION);
    } finally {
      if (session != null && session.isOpen()) {
        session.close();
      }
    }
    return rezult;
    }

}


Цитата(ivanovpv @  10.11.2009,  09:32 Найти цитируемый пост)

А вообще зря вы от Hibernate отошли. Раз вы сами напрямую лезете в базу - на кой ляд он вам нужен? Тот же PreparedStatement можно реализовать средствами Hibernate (см. выше)


Пришлось "извращаться" для скорости.Вот в том извращенном варианте таблица строится за 4 сек, а в том что как-бы вроде полюдски сделал(чуть выше) ~20 сек..


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0614 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.