編輯:基於我的一些調試和日誌記錄,我認爲這個問題歸結爲爲什麼DELETE FROM table WHERE id = x
比DELETE FROM table WHERE id IN (x)
快得多,其中x
只是一個單一的ID。Hibernate批量刪除vs單一刪除
我最近測試了批量刪除與刪除每行一個接一個,發現批量刪除是慢得多。該表具有刪除,更新和插入的觸發器,但我已經測試過,沒有觸發器,每次批量刪除都比較慢。 任何人都可以闡明爲什麼這是這種情況或分享提示如何我可以調試呢?根據我的理解,我不能真正減少觸發器激活的次數,但我最初認爲降低「刪除」查詢的數量將有助於提高性能。
我已經包括下面的一些信息,請讓我知道如果我漏掉了任何相關信息。
刪除在10000批次,代碼看起來像做:
private void batchDeletion(Collection<Long> ids) {
StringBuilder sb = new StringBuilder();
sb.append("DELETE FROM ObjImpl WHERE id IN (:ids)");
Query sql = getSession().createQuery(sb.toString());
sql.setParameterList("ids", ids);
sql.executeUpdate();
}
刪除一個單行的代碼基本上是:
SessionFactory.getCurrentSession().delete(obj);
表有兩個指標是不用於任何刪除。不會發生級聯操作。
下面是一個樣本的EXPLAIN分析DELETE FROM table where id IN (1, 2, 3);
:
Delete on table (cost=12.82..24.68 rows=3 width=6) (actual time=0.143..0.143 rows=0 loops=1)
-> Bitmap Heap Scan on table (cost=12.82..24.68 rows=3 width=6) (actual time=0.138..0.138 rows=0 loops=1)
Recheck Cond: (id = ANY ('{1,2,3}'::bigint[]))
-> Bitmap Index Scan on pk_table (cost=0.00..12.82 rows=3 width=0) (actual time=0.114..0.114 rows=0 loops=1)
Index Cond: (id = ANY ('{1,2,3}'::bigint[]))
Total runtime: 3.926 ms
我吸塵,每次我重裝我的數據進行測試的時間重新索引和我的測試數據中包含386660行。
測試是刪除所有行,我沒有使用TRUNCATE
,因爲通常有一個選擇標準,但出於測試目的,我已經使標準包括所有行。啓用觸發器後,逐行刪除每行193,616ms,批量刪除耗時285,558ms。然後我禁用了觸發器,得到93,793ms的單行刪除和181,537ms的批量刪除。觸發器會彙總值並更新另一個表格 - 基本上是簿記。
我打得四處低批量(100和1),它們似乎都表現較差。
編輯:原來Hibernate的日誌記錄和單行的行刪除,它基本上做:delete from table where id=?
和EXPLAIN分析一下:
Delete on table (cost=0.00..8.31 rows=1 width=6) (actual time=0.042..0.042 rows=0 loops=1)
-> Index Scan using pk_table on table (cost=0.00..8.31 rows=1 width=6) (actual time=0.037..0.037 rows=0 loops=1)
Index Cond: (id = 3874904)
Total runtime: 0.130 ms
編輯:很好奇,如果該列表實際上包含萬ID,如果Postgres的會做一些不同的事情:不要。
Delete on table (cost=6842.01..138509.15 rows=9872 width=6) (actual time=17.170..17.170 rows=0 loops=1)
-> Bitmap Heap Scan on table (cost=6842.01..138509.15 rows=9872 width=6) (actual time=17.160..17.160 rows=0 loops=1)
Recheck Cond: (id = ANY ('{NUMBERS 1 THROUGH 10,000}'::bigint[]))
-> Bitmap Index Scan on pk_table (cost=0.00..6839.54 rows=9872 width=0) (actual time=17.139..17.139 rows=0 loops=1)
Index Cond: (id = ANY ('{NUMBERS 1 THROUGH 10,000}'::bigint[]))
Total runtime: 17.391 ms
編輯:基於以上的EXPLAIN ANALYZE,我從實際的刪除操作中檢索了一些日誌記錄。以下是逐行刪除的兩個變體的日誌記錄。
下面是一些單個刪除:
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
2013-03-14 13:09:25,424:delete from table where id=?
這裏是單刪除的其他變化(列表中僅有1項)
2013-03-14 13:49:59,858:delete from table where id in (?)
2013-03-14 13:50:01,460:delete from table where id in (?)
2013-03-14 13:50:03,040:delete from table where id in (?)
2013-03-14 13:50:04,544:delete from table where id in (?)
2013-03-14 13:50:06,125:delete from table where id in (?)
2013-03-14 13:50:07,707:delete from table where id in (?)
2013-03-14 13:50:09,275:delete from table where id in (?)
2013-03-14 13:50:10,833:delete from table where id in (?)
2013-03-14 13:50:12,369:delete from table where id in (?)
2013-03-14 13:50:13,873:delete from table where id in (?)
兩者都是的ID存在於該表,並應是連續的。
EXPLAIN分析DELETE FROM table WHERE id = 3774887;
Delete on table (cost=0.00..8.31 rows=1 width=6) (actual time=0.097..0.097 rows=0 loops=1)
-> Index Scan using pk_table on table (cost=0.00..8.31 rows=1 width=6) (actual time=0.055..0.058 rows=1 loops=1)
Index Cond: (id = 3774887)
Total runtime: 0.162 ms
EXPLAIN分析DELETE FROM table WHERE id IN (3774887);
Delete on table (cost=0.00..8.31 rows=1 width=6) (actual time=0.279..0.279 rows=0 loops=1)
-> Index Scan using pk_table on table (cost=0.00..8.31 rows=1 width=6) (actual time=0.210..0.213 rows=1 loops=1)
Index Cond: (id = 3774887)
Total runtime: 0.452 ms
0.162 VS 0.452認爲顯著差異?
編輯:
設置批量50,000和Hibernate不喜歡這個主意:
java.lang.StackOverflowError
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:40)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:41)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:42)
....
看來,當你刪除單行它使用其他索引。你能檢查它嗎? – ntalbs 2013-03-14 00:51:01
我已經添加了關於單行逐行刪除的信息。表格的MAX(id)是3774904,所以我選擇了一個更大的數字。我嘗試使用低於3774904的ID,但不在表中,得到了類似的結果(表中的ID類似)。 – nevets1219 2013-03-14 17:23:31
是的,0.162對0.452 *是顯着的,因爲0.452幾乎是0.162的3倍。特別有趣的是,解釋表明他們正在做同樣的事情。我會用postgresql團隊提出這個問題。 [pgsql-general](http://www.postgresql.org/community/lists/)可能是個好地方 – 2013-03-20 09:43:18