I have the problem that a bulk read from a database is getting slower and slower the more objects I read. I have a simple object model:
Book, Author and Chapters. A book has OneToMany Authors and OneToMany Chapters.
My test case is to create 10000 books each having 10 authors and 10 chapters. The book title, chapter content and author name are short strings (around 10chars length).
Then I try to read all books (including authors and chapters). All classes have toString methods that print all properties. To prevent IO bottlenecks I call the toString method of the book (therefore retrieving all lazy collections) but do not print the content somewhere (I did before, did not change the numbers a lot).
I am logging how long the retrieval of 100 books takes and the times (in ms) are:
Code:
39;692;438;433;568;484;587;635;660;489;
552;542;555;603;602;764;537;845;627;642;
561;605;680;660;578;603;698;636;697;710;
827;770;785;872;951;879;894;934;970;1101;
1010;1067;1097;1133;1249;1196;1230;1352;1314;1661;
1545;1395;1420;1461;1538;1633;1615;1611;1643;1712;
1721;1831;1901;1987;2024;2061;2112;2145;2263;2186;
2210;2262;2300;2339;2368;2539;2427;2466;2523;2756;
2755;2599;2696;2800;2702;2771;2782;2819;2819;2868;
2951;3262;2962;3025;2991;3109;3115;3572;3406;3483;3565;
(first number for first 100 books, second for books 100-200)
Some statistical ups and downs, but the tendency is raising: books 9900 to 10000 take about 4 times longer to read than books 0-100!
The numbers above are for MySql, same tendency for Oracle9 (but generally slower).
The question is: why is getting hibernate (?) slower on more objects??? I clear the session cache, I do not use a 2nd level cache - I have no idea what is going on. But it prevents us from using hibernate in a large project!
My classes and settings:
Code:
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
@Basic
private String title;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List<Author> authors;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List<Chapter> chapters;
// getters and setters
}
@Entity
public class Author {
@Id
@GeneratedValue
private Long id;
private String name;
// getters and setters
}
@Entity
public class Chapter {
@Id
@GeneratedValue
private Long id;
@Basic
private String text;
// getters and setters
}
Code between sessionFactory.openSession() and session.close():Code:
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
String hql = "select b from Book b where b.title LIKE 'book%'";
Query query = session.createQuery(hql).setCacheMode(CacheMode.IGNORE);
ScrollableResults books = query.scroll(ScrollMode.FORWARD_ONLY);
int count=0;
Book book;
String bookString;
while ( books.next() ) {
book = (Book) books.get(0);
bookString = count + " " + book;
if (count % 25 == 0) {
//flush and release memory:
session.flush();
session.clear();
}
++count;
}
tx.commit();
session.close();
My hibernate.hbm.xml looks like:
Code:
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://xxxx/aptest?useUnicode=true&characterEncoding=UTF-8</property>
<property name="connection.username">xx</property>
<property name="connection.password">xx</property>
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- batch inserts -->
<property name="hibernate.jdbc.batch_size">25</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>
<property name="hbm2ddl.auto">validate</property> <!-- create, update, validate -->
<!-- for configuration in annotations -->
<mapping class="testonetomany.Book"/>
<mapping class="testonetomany.Author"/>
<mapping class="testonetomany.Chapter"/>
</session-factory>
</hibernate-configuration>
Hibernate version: 3.2.3.ga, hibernate annotations 3.2.1.ga
Name and version of the database you are using:mysql-5.0.18 (linux on suse) or oracle 9g
Code: