jdon 的分页机制的效率低,

smallyi 07-04-23

c = dataSource.getConnection();

DbUtil.testConnection(c);
ps = c.prepareStatement(qcdk.getSqlquery(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

jdbcUtil.setQueryParams(qcdk.getQueryParams(), ps);

rs = ps.executeQuery();
if (DbUtil.supportsFetchSize)
rs.setFetchSize(blockSize);
// Many JDBC drivers don't implement scrollable cursors the real
// way, but instead load all results into memory. Looping through
// the results ourselves is more efficient.
for (int i = 0; i < blockStart; i++) {
if (!rs.next()) break;
}
blockSize ++;
while(rs.next() && (--blockSize > 0)) {
Object result = rs.getObject(1);
logger.debug("[JdonFramework]--> found a primary key = " + result + ", type:" + result.getClass().getName());
items.add(result);
}

logger.debug("[JdonFramework]--> get a result succefully ..");

一次取出所有的记录,然后遍历内存取

smallyi
2007-04-23 11:25

hibernate中通过对不同数据库中统一接口设计,实现了透明化,通用化的分页实现机制。通过针对不同的dialect(数据库方言),来实现hibernate高度的可移植性。
可以通过Criteria.setFirstResult和Criteria.setFetchSize方法设定分页范围

eg.

Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq("age","20"));
//从检索结果中获取第100条记录开始的20条记录
criteria.setFirstResult(100);
criteria.setFetchSize(20);

Hibernate中,抽象类net.sf.hibernate.dialect指定了所有底层数据库的对外统一接口。通过针对不同数据库提供相应的dialect实现,数据库之间的差异性得以消除,从而为上层机制提供了透明的、数据库无关的存储层基础。

对于分页机制而言, dialect中定义了一个getLimitString方法,此方法用于在现有Select 语句基础上,根据各数据库自身特性,构造对应的记录返回限定子句。如MySQL中对应的记录限定子句为Limit,而Oracle中,可通过rownum 子句实现。

我们来看MySQLDialect中的getLimitString实现:

public String getLimitString(String sql, boolean hasOffset) {return new StringBuffer( sql.length()+20 ).append(sql).append( hasOffset ? " limit ?, ?" : " limit ?").toString();}
从上面可以看到,MySQLDialect.getLimitString方法的实现实际上是在给定的Select语句后追加MySQL所提供的专有SQL子句limit来实现。

通过Oracle 特有的rownum子句可以实现了数据的部分读取:

public String getLimitString(String sql, boolean hasOffset){StringBuffer pagingSelect =new StringBuffer( sql.length()+100 );if (hasOffset) {pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");}else {pagingSelect.append("select * from ( ");}pagingSelect.append(sql);if (hasOffset) {pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");}else {pagingSelect.append(" ) where rownum <= ?");}return pagingSelect.toString();}
大多数主流数据库都提供了数据部分读取机制,而对于某些没有提供相应机制的数据库而言,Hibernate也通过其他途径实现了分页,如通过 Scrollable ResultSet,如果JDBC 不支持Scrollable ResultSet,Hibernate 也会自动通过ResultSet 的next 方法进行记录定位。这样,Hibernate 通过底层对分页机制的良好封装,使得开发人员无需关心数据分页的细节实现,将数据逻辑和存储逻辑分离开来,在提高生产效率的同时,也大大加强了系统在不同数据库平台之间的可移植性。

简单举例:

Query query = _session.createQuery(hql.toString());

query.setMaxResults(limit).setFirstResult(row).list();

这是常用的方法。

banq
2007-04-23 12:38

多谢对JdonFramework的建议。

jdon 的分页机制有两个部分组成:缓存和你楼上指出的JDBCTemp中语句。

JdbcTemp效率是低的,但是结合缓存以后,整个Jdon分页机制在大并发访问下,效率是并不低的。

什么道理呢?
在一个反复访问中系统中,只要我们业务对象设计科学,缓存利用率高,那么JdbcTemp SQL语句低效率只影响一次。100个用户中碰到这第一次概率是1%。

当然,如果精益求精,可以提高这第一次效率,比如持久层使用Hibernate等其他技术都可以,JdonFramework重点在业务层。

那有人问了,你为什么不提高你的第一次呢?狠显然,如果为这1%提高效率,投入的精力和代码规模就狠大,代码复杂性就很大,看看Hibernate就知道,而且Hibernate已经做了,就不必再重复发明轮子。

反过来再说Hibernate,如果不激活二级缓存,以及良好的实体对象设计,不结合Jdon等框架缓存,Hibernate性能也很慢,这在本站有很多帖子已经讨论到。


总之:性能问题不只是集中在数据库层,以及数据库SQL语句的效率上,这是数据库思维导致,重点应该在对象构建上,以及对象重用性上。这个观点我已经反复声明,可见其他帖子。

[该贴被banq于2007年04月23日 12:49修改过]