今天花了一天的時候測試batch-size和hibernate.jdbc.batch_size這個屬性.
首先說說 hibernate.jdbc.batch_size 這個屬性.
這個屬性的使用場合是大量匯入資料或大量刪除時使用.其實就是相當於使用PreparedStatement.executeBatch()方法..將數個sql語句一起提交獲得效能上的提高. hibernate.jdbc.batch_size在hibernate.cfg.xml中設定.
大量匯入資料代碼.
// for(int i=0;i<25;i++ ){
// UserInfo u = new UserInfo();
// u.setUserName("dengyin"+ i);
// u.setPassword("sdfa");
// u.setEmail("dasfa");
// session.save(u);
// if (i%25==0){
// session.flush();//每進行完25條時flush session和清空緩衝. 這樣可以避免記憶體溢出(假如資料構多的話)
// session.clear();//晴空緩衝
// }
//
// }
batch-size可以設定在Hbm的class 和 集合定義中. 開始我一直以為batch-size是擷取child的數量, 其實真正擷取的是parent的數量.
但是奇怪的是當我測試時 我把batch-size的值從1設定到5, 當設成1和2時其實每次擷取的還是一個parent.當到3時就是同時擷取3個parent.當多出select出來的parent時,感覺好像就沒有規律了.我建議一般都把batch-size設成3
下面的來自hibernate文檔.(奇怪的是hibernate中文文檔並沒有關於 batch fetching 的介紹.)
Hibernate can make efficient use of batch fetching, that is, Hibernate can load several uninitialized proxies if one proxy is accessed. Batch fetching is an optimization for the lazy loading strategy. There are two ways you can tune batch fetching: on the class and the collection level.
Batch fetching for classes/entities is easier to understand. Imagine you have the following situation at runtime: You have 25 Cat instances loaded in a Session, each Cat has a reference to its owner, a Person. The Person class is mapped with a proxy, lazy="true". If you now iterate through all cats and call getOwner() on each, Hibernate will by default execute 25 SELECT statements, to retrieve the proxied owners. You can tune this behavior by specifying a batch-size in the mapping of Person:
<class name="Person" lazy="true" batch-size="10">...</class>
Hibernate will now execute only three queries, the pattern is 10, 10, 5. You can see that batch fetching is a blind guess, as far as performance optimization goes, it depends on the number of unitilized proxies in a particular Session.
You may also enable batch fetching of collections. For example, if each Person has a lazy collection of Cats, and 10 persons are currently loaded in the Sesssion, iterating through all persons will generate 10 SELECTs, one for every call to getCats(). If you enable batch fetching for the cats collection in the mapping of Person, Hibernate can pre-fetch collections:
<class name="Person"> <set name="cats" lazy="true" batch-size="3"> ... </set></class>
With a batch-size of 3, Hibernate will load 3, 3, 3, 1 collections in 4 SELECTs. Again, the value of the attribute depends on the expected number of uninitialized collections in a particular Session.
Batch fetching of collections is particularly useful if you have a nested tree of items, ie. the typical bill-of-materials pattern.
跟蹤了一下代碼.
net.sf.hibernate.loader.BatchingCollectionInitializer的public void initialize(Serializable id, SessionImplementor session)方法.
public void initialize(Serializable id, SessionImplementor session)
throws SQLException, HibernateException {
Serializable[] batch = session.getCollectionBatch(collectionPersister, id, batchSize);
if ( smallBatchSize==1 || batch[smallBatchSize-1]==null ) {
nonBatchLoader.loadCollection( session, id, collectionPersister.getKeyType() );
}
else if ( batch[batchSize-1]==null ) {
if ( log.isDebugEnabled() ) log.debug( "batch loading collection role (small batch): " + collectionPersister.getRole() );
Serializable[] smallBatch = new Serializable[smallBatchSize];
System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
smallBatchLoader.loadCollectionBatch( session, smallBatch, collectionPersister.getKeyType() );
log.debug("done batch load");
}
else {
if ( log.isDebugEnabled() ) log.debug( "batch loading collection role: " + collectionPersister.getRole() );
batchLoader.loadCollectionBatch( session, batch, collectionPersister.getKeyType() );
log.debug("done batch load");
}
}
當smallBatchSize=1時其實是到了nonBatchLoader.loadCollection( session, id, collectionPersister.getKeyType() );裡面. 這裡的話就是初始一個ID而已. 我發現當batch-size=2時 smallBatchSize是=1的.
int smallBatchSize = (int) Math.round( Math.sqrt(batchSize) );//OneToManyPersister.java 182行.
這個是smallBatchSize的取值.