hibernate的问题

03-09-10 chinahero
各位老大,我测了一下hibernate和直接用jdbc取mysql的数据

目的是:从表的10000条记录处取100条,看时间

1.用jdbc取数据

Class.forName("org.gjt.mm.mysql.Driver");

String url="jdbc:mysql://10.0.18.93/test";

String user = "root";

String password = "hello";

Connection conn = DriverManager.getConnection(url, user, password);

Statement stmt = conn.createStatement();

long begintime=System.currentTimeMillis();

ResultSet rs = stmt.executeQuery("select * from post limit 10000,100");

long endtime=System.currentTimeMillis();

System.out.println("query cost time="+(endtime-begintime));

结果:query cost time=235

2.用hibernate

sql = "select post from my.test.Post as post ";

long begintime = System.currentTimeMillis();

System.out.println("Begin time is " + begintime);

query = session.createQuery(sql);

query.setFirstResult(10000);

query.setMaxResults(100);

List catList = query.list();

long middletime = System.currentTimeMillis();

System.out.println("Query cost time is " +

(middletime - begintime));

结果:Query cost time is 8391

使用hibernate的全部代码

public class HibernateMain {

private static SessionFactory sessionFactory;

private static Session session;

private static Transaction transaction;

public static void main(String[] args) {

HibernateMain hm = new HibernateMain();

try {

hm.initHibernate();

session = sessionFactory.openSession();

//取出贴子条数

String sql = "select count(*) from com.alibaba.bizclub.dbo.Post as post ";

Query query = session.createQuery(sql);

Integer count = (Integer) query.iterate().next();

//取出贴子内容

sql = "select post from my.test.Post as post ";

long begintime = System.currentTimeMillis();

System.out.println("Begin time is " + begintime);

query = session.createQuery(sql);

query.setFirstResult(10000);

query.setMaxResults(100);

List catList = query.list();

long middletime = System.currentTimeMillis();

System.out.println("Query cost time is " +

(middletime - begintime));

for (Iterator it = catList.iterator(); it.hasNext();) {

Post post = (Post) it.next();

}

long endtime = System.currentTimeMillis();

System.out.println("End cost time is " + (endtime - begintime));

} catch (HibernateException ee) {

ee.printStackTrace();

}

}

private void initHibernate() throws HibernateException {

sessionFactory = new Configuration().configure().buildSessionFactory();

}

}

iceant
2003-09-10 10:47
把这一句放到后面去或注释掉会更准确 System.out.println("Begin time is " + begintime);

因为 System IO 也要花时间。

yehs220
2003-09-10 10:50
1 测试方法太粗糙

2 ResultSet rs = stmt.executeQuery("select * from post limit 10000,100");

这并没有实际取出数据

chinahero
2003-09-10 11:03
stmt.executeQuery("select * from post limit 10000,100");

能取到数据的

我看过了这里另一个关于性能的贴子,有两点

1.mysql的jdbc驱动有问题,所以极快?

2.hibernate是不是默认不打开jcs的,所以性能一般,如何打开jcs?

yehs220
2003-09-10 11:09
stmt.executeQuery()只是返回一个ResultSet,

你需要遍历这个ResultSet并取出每个字段。

jcs看看hibernate的文档

robbin
2003-09-10 12:24
To: Chinahero

你的测试例子写的不对,所以这样的测试出来的结果有极大的误导性。

robbin
2003-09-10 12:26
对了,如果你对自己的测试有信心的话,证实了JDBC的速度远远超过Hibernate,可以给Gavin King发信,赢取100美元的奖金。

chinahero
2003-09-10 12:47
我就是觉的奇怪啊,为什么会这样,我错在哪里?

chinahero
2003-09-10 13:30
我想这样测一下,肯定是有问题的,能不能说一下我的问题

我的目的是从mysql的一个post表中取10000-10100条记录

问题在哪呀

虚心请假各位老大

yehs220
2003-09-10 13:35
你需要遍历ResultSet并取出每个字段。

多次测试取平均,偏差太大的测试要剔除...

还有很多技巧,我也不是很清楚

oldma
2003-09-10 13:39
比较准确地用statement的方法如下,有兴趣你可以试一试

以oracle数据库为例

Statement stmt = conn.createStatement();

long begintime=System.currentTimeMillis();

ResultSet rs = stmt.executeQuery("select * from post where rownum < 10000");

Post post = null;

ArrayList list= new ArrayList ();

int i =0;

while(rs.next && i<100){

post = new Post();

post.set...(rs.get...());

post.set...(rs.get...());

list.add(post);

i++;

}

long endtime=System.currentTimeMillis();

System.out.println("query cost time="+(endtime-begintime));

不知道my-sql有没有rownum这种伪列

还有一点就是JDBC并不是在rs.get时才取数据的,而是在stmt.executeQuery()取的,当让,大部分JDBC的API可以通过

stmt.setPreFetch...()来设定stmt.executeQuery()第一次获得的纪录条数。这个stmt不是java.sql.Statement接口,而是具体的实现类。

yehs220
2003-09-10 14:12
>还有一点就是JDBC并不是在rs.get时才取数据的,而是在stmt.executeQuery()取的<

我也不是很清楚在stmt.executeQuery()时是否会取出数据,

但至少不会取出所有数据(当rows>fetchSize时)

robbin
2003-09-10 14:31
你的测试里面至少有3个明显的错误:

一、生成的SQL语句都不同

JDBC用的sql是MySQL数据库专用的sql语句,是在数据库里面分页,驱动只从数据库里面取100条记录出来;而Hibernate的sql是通用sql,你看看我前面一个Hibernate性能测试的帖子,分析过MySQL驱动的缺陷问题,在Hibernate List方式下,MySQL驱动会把10100条记录全部取出。简单的心算一下,两者就有101倍的速度差距了,怎么比阿?

要做性能对比,最起码的一点是两者产生的sql语句必须一样,否则还比什么?表面上在做JDBC vs Hibernate的测试,实际上在做 两个不同SQL语句之间的性能测试。

Hibernate是一个通用持久层框架,它不可能把MySQL专用的sql语句包含进来,Hibernate2.1beta版的HQL引入了native sql,不知道能不能在HQL里面用MySQL的专用limit分页,你可以试试。

这是造成测试结果差异的主要原因,当然还有其它的错误。

二、结果集遍历速度

你的测试只测了从数据库取结果集的速度,而没有测试结果集的遍历速度。看看我前面那个帖子,详细分析了这个问题。JDBC的结果集的获取由于驱动的缺陷,要比Hibernate List快一个以上的数量级,但是JDBC结果集的遍历速度可比Hibernate List方式差远了。 你可以分别测试一下结果集获取速度和结果集遍历速度,我前面曾经测试过, Hibernate List方式下的结果集遍历,30万条记录的遍历速度还不到100ms,而JDBC遍历30万条记录的结果集需要10几秒,两者相差何止两个数量级?

三、 load Class的IO问题

如果用Java主程序来测试,那么必须连续测试多次,抛弃第一次结果,后面的结果取平均。为什么要连续测试?为什么要抛弃第一次结果?

因为Java load Class是一种按需加载,不到必须使用的时候,不会去load class,当你启动测试程序,JVM被启动,依次加载用到的Class,这包括MySQL的JDBC驱动,包括rt.jar,以及其它用到的Class。

在JDBC测试的两个计时过程中,当第一次测试被运行的时候,有关Statement, ResultSet等等一些Class被加载到JVM的内存里面去,这个加载需要时间,如果被加载的Class预先没有被读入内存,甚至需要硬盘IO过程。

而Hibernate用到的类库,比JDBC多了差不多5MB左右,那意味着第一次测试过程中,Hibernate要多load 5MB的数据到内存,不计算Class的验证过程,光是5MB的数据的硬盘IO,你算算要多多少时间?

所以要连续测试,第二次测试的时候,所有的Class已经被load完毕,就排除了load Class带来的测试偏差。

yehs220
2003-09-10 14:42
同意robbin

>它不可能把MySQL专用的sql语句包含进来,Hibernate2.1beta版的HQL引入了native sql<

只要在hibernate.properties中设置了

hibernate.dialect net.sf.hibernate.dialect.MySQLDialect

分页时就会采用limit

native是指session.createSQLQuery(queryString)时在queryString中

采用limit,rownum之类的native sql

banq
2003-09-10 14:51
hibernate 的list()方法执行后,返回的是数据对象Java Object,而你的JDBC返回的是ResultSet。

你应该在JDBC测试程序后加上Java Object的组装。再测试看看,估计new对象时要花费一些时间。

猜你喜欢
3Go 1 2 3 下一页