hibernate的批量删除,大家怎么做的?

有个业务要求,需要批量删除,找了半天,没有找到,只有一个近似的,
是利用主子表的方式,删除所有子表。

session.delete("from Cat as c where ...");

把 hibernate.jdbc.batch_size 50 尽量设的大些,可以得到接近JDBC的删除速度。

>可以得到接近JDBC的删除速度<

我觉得不可能,hibernate要先select出来,再delete。

还是写jdbc来做batch delete,update吧

可不可能自己试试就知道了。

我的测试:

Oracle817,ojdbc14.jar 表记录1万条,全部删除。

JDBC:

sql语句 delete from cat
速度:平均6s

Hibernate:

session.delete("from Cat as c");
==> select id,name,sex,weight from cat;
==> delete from cat where id = ?

Batch Size = 0 速度: 25s
Batch Size = 50 速度: 6s

是这样,看了源代码,是查一条删一条:(。

速度接近是不是因为查询缓存的缘故?

不过速度接近,倒是可以直接使用。这个论坛好像不能编辑自己的帖子。

批量更新和批量删除都因为要对PO同步的缘故,所以是ORM固有的缺点,但是我想说的是,Hibernate在批量更新和批量删除的时候,效率并非很糟糕,只有优化好,一样可以得到近似JDBC的速度。

在比较速度之前,以下问题你考虑到了吗?
1。connection pool
获得数据库连接是很慢的,hibernate应该是用connection pool,jdbc用了吗?
2。index
批量删除一定要屏蔽索引,否则数据库就是索引里查一条表里删一条(像hibernate?),如果没有屏蔽索引,速度慢也正常。

你说呢?

挺自信呀,
不管你怎样优化,hibernate的批量删除都要
1.先查询数据,构造很多对象,
2.然后执行batch operation

而正确的jdbc批量删除只要执行一个删除sql语句,

对于数据库来说
执行一个删除sql语句 的时间 要远小于一个batch operation
原因很简单,对于决大多数jdbc ,batch operation只是将多条
数据库操作一次发到db server,避免多次网络连接,而到了数据库
之后还是一条一条执行,每一条执行都是一次表扫描,性能远小于执行一个删除sql语句。

你的测试时间接近,是你的表简单了,换一个复杂的表试一试吧

可以肯定,用jdbc批量删除要比hibernate好很多,其实没法比
前提:用一个sql或有限的几个sql来完成批量删除。

b t w
需要这么酷吗?


你上面的说的那两点考虑因素如果连这个都没有想到,那岂不是成了弱智?

很早之前的一个帖子里面我就说过批量删除和批量更新建议用JDBC,这是一个原则,当然有的时候可能必须用Hibernate来批量更新和批量删除,那么这个时候我想说的就是,Hibernate批量更新和删除效率并非传说中的那么差,只要优化的好,速度也非常快。

Hibernate先查询数据,确实要消耗一些时间,但是select只读操作和insert,delete,update这些数据库修改操作在速度上有一个以上的数量级的差距。所以Hibernate虽然查询数据要多耗时,但是消耗的这点时间影响不是很大,主要是内存消耗的多。

JDBC: delete from table_name; 这个sql不清楚数据库是怎么进行解析和执行的,从我多次的测试来看,Oracle似乎内部也是把主键找出来,然后按照主键依次删除(即使没有主键,也有rownum之类的东西),这样来看,其实和Hibernate的删除方式没有本质差别,Hibernate主要差距在PO的同步和多次的网络通讯数据传输上。其实当删除大量数据的时候,主要的瓶颈在数据库的硬盘IO上,所以以上的那些差距影响因素就显得不那么重要了,这也是为什么Hibernate批量删除速度有可能接近JDBC的原因。

BTW:Oracle的delete语句其实是很慢的,truncate才是快速删除


〉其实当删除大量数据的时候,主要的瓶颈在数据库的硬盘IO上
非常同意这个说法,我只是在说明以下这个问题

case 1
delete from tab where id = 1
delete from tab where id = 2
delete from tab where id = 3
delete from tab where id = 4
delete from tab where id = 5
...
delete from tab where id = 10000

case 2
delete from tab where id+0 =< 10,000

case 2 的执行效率要高很多尤其是表数据大于100,000时

如果hibernate的删除是case 1的话,那还是用索引比较好(每一条
的定位不需要做全表扫描)。

对于case 2,快的原因是一次全表扫描删除了所有10000行

呵呵,我也是hibernate的忠实拥护者。

BTW:tracunt(忘了怎么拼的了)是表截断,根本不做全表扫描,当然快
可表里一条数据也剩不下了。

Hibernate删除采取case 1,由于id本来就是主键,所以和索引没有什么关系。JDBC 我用case2的sql语句。但是我上面的帖子其中谈到,我的经验告诉我,case2的sql语句实际上也是转换为case1来执行的,我会在Oracle上测试一下,验证是否如此,晚些时候贴上来结果。