編集:私のデバッグとロギングのいくつかに基づいて、質問は、単一のIDがどこにあるDELETE FROM table WHERE id = x
かよりもはるかに速い理由に要約されると思います。DELETE FROM table WHERE id IN (x)
x
最近、バッチ削除と各行を1つずつ削除することをテストしましたが、バッチ削除の方がはるかに遅いことに気付きました。テーブルには削除、更新、挿入のトリガーがありましたが、トリガーがある場合とない場合でテストし、バッチ削除が遅くなるたびにテストしました。誰かがこれが事実である理由に光を当てたり、これをデバッグする方法に関するヒントを共有したりできますか?私が理解していることから、トリガーがアクティブになる回数を実際に減らすことはできませんが、「削除」クエリの数を減らすとパフォーマンスが向上すると当初は考えていました。
以下にいくつかの情報を記載しました。関連する情報がない場合はお知らせください。
削除は10,000のバッチで行われ、コードは次のようになります。
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();
}
基本的に、1行だけを削除するコードは次のとおりです。
SessionFactory.getCurrentSession().delete(obj);
テーブルには、どの削除にも使用されない2つのインデックスがあります。カスケード操作は発生しません。
これがEXPLAINANALYZEのサンプルです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
テストのためにデータをリロードするたびにバキュームしてインデックスを再作成しましたが、テストデータには386,660行が含まれています。
テストはすべての行を削除するTRUNCATE
ことであり、通常は選択基準があるため使用していませんが、テストの目的で、基準にすべての行を含めるようにしました。トリガーを有効にすると、各行を1つずつ削除するのに193,616ミリ秒かかりましたが、バッチ削除には285,558ミリ秒かかりました。次に、トリガーを無効にして、単一行の削除で93,793ミリ秒、バッチ削除で181,537ミリ秒を取得しました。トリガーが実行され、値が合計され、別のテーブル(基本的には簿記)が更新されます。
私はより低いバッチサイズ(100と1)で遊んだことがありますが、それらはすべてパフォーマンスが悪いようです。
編集:Hibernateロギングをオンにし、行ごとの削除については、基本的に次のことを行っています:delete from table where id=?
そしてEXPLAIN ANALYZE:
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
編集:リストに実際に10,000 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に基づいて、実際の削除操作からいくつかのログを取得しました。以下は、単一行ごとの削除の2つのバリエーションのログです。
いくつかの単一の削除は次のとおりです。
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であり、シーケンシャルである必要があります。
の説明分析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
の説明分析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対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)
....