2013-03-14 5 views
10

संपादित करें: मेरे कुछ डिबगिंग और लॉगिंग के आधार पर, मुझे लगता है कि DELETE FROM table WHERE id = xDELETE FROM table WHERE id IN (x) से बहुत तेज़ क्यों है, जहां x केवल एक आईडी है।हाइबरनेट बैच-डिलीट बनाम सिंगल डिलीट

मैंने हाल ही में प्रत्येक पंक्ति को एक-एक करके हटाकर बैच-डिलीट का परीक्षण किया और देखा कि बैच-डिलीट बहुत धीमा था। तालिका को हटाने, अपडेट करने और डालने के लिए ट्रिगर्स थे, लेकिन मैंने ट्रिगर्स के साथ और बिना परीक्षण किया है और प्रत्येक बार बैच-डिलीट धीमा था। क्या कोई इस बात पर कुछ प्रकाश डाल सकता है कि यह मामला क्यों है या मैं इसे कैसे डिबग कर सकता हूं इस पर साझा सुझाव? जो मैं समझता हूं, मैं वास्तव में ट्रिगर सक्रिय होने की संख्या को कम नहीं कर सकता लेकिन मुझे मूल रूप से यह पता चला था कि "हटाएं" क्वेरी की संख्या को कम करने से प्रदर्शन में मदद मिलेगी।

मैंने नीचे कुछ जानकारी शामिल की है, कृपया मुझे बताएं कि क्या मैंने कुछ भी प्रासंगिक छोड़ दिया है।

विलोपन 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(); 
} 

सिर्फ एक ही पंक्ति को हटाने के लिए कोड मूल रूप से है:

SessionFactory.getCurrentSession().delete(obj); 

तालिका के इंडेक्स है जो है किसी भी विलोपन में उपयोग नहीं किया जाता है। कोई कैस्केड ऑपरेशन नहीं होगा।

यहाँ का एक नमूना है व्याख्या 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 

मैं वैक्यूम कर दिया है और हर बार मैं परीक्षण के लिए अपने डेटा को फिर से लोड reindexed और मेरे परीक्षण डाटा 386,660 पंक्तियां हैं।

परीक्षण सभी पंक्तियों को हटाना है और मैं TRUNCATE का उपयोग नहीं कर रहा हूं क्योंकि आम तौर पर चयन मानदंड होते हैं लेकिन परीक्षण उद्देश्यों के लिए, मैंने मानदंडों को सभी पंक्तियों को शामिल किया है। ट्रिगर्स सक्षम होने के साथ, प्रत्येक पंक्ति को एक-एक करके हटाकर 1 9 3,616ms लिया गया जबकि बैच-डिलीट 285,558ms लिया गया। इसके बाद मैंने ट्रिगर्स को अक्षम कर दिया और बैच-डिलीट के लिए एकल पंक्ति डिलीट के लिए 93,793ms और 181,537ms प्राप्त किए। ट्रिगर जाता है और मानों को जोड़ता है और दूसरी तालिका अपडेट करता है - मूल रूप से बहीखाता।

मैंने निचले बैच आकार (100 और 1) के साथ खेला है और वे सभी खराब प्रदर्शन करते हैं।

संपादित करें: हाइबरनेट लॉगिंग और पंक्ति से ही पंक्ति के लिए निकला हटाता है, यह मूल रूप से कर रहा है: delete from table where id=? और व्याख्या विश्लेषण:

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 

संपादित करें: यदि Postgres होगा, अगर सूची वास्तव में 10,000 आईडी है उत्सुक था कुछ अलग करो: नहीं।

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 

संपादित करें: के आधार पर ऊपर की विश्लेषण की व्याख्या, मैं वास्तविक हटाने संचालन से कुछ प्रवेश लिया गया है। पंक्ति पंक्तियों द्वारा एकल पंक्ति के दो भिन्नता के नीचे लॉगिंग है।

यहाँ कुछ भी हटाए गए हैं:

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=? 

यहाँ एक हटाता के अन्य भिन्नता है

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 (?) 

(सूची सिर्फ 1 आइटम है) दोनों आईडी तालिका में मौजूद है और ऐसा करना चाहिए रहे हैं क्रमिक हो।


व्याख्या 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 

का विश्लेषण बनाम 0.452 माना महत्वपूर्ण अंतर 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 के विश्लेषण के बारे में बताएं?

संपादित करें:

बैच सेट आकार 50,000 और हाइबरनेट कि विचार पसंद नहीं आया:

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) 
.... 
+0

ऐसा लगता है कि जब आप एकल पंक्ति को हटाते हैं तो यह अन्य अनुक्रमणिका का उपयोग करता है। क्या आप इसकी जाँच कर सकते हैं? – ntalbs

+0

मैंने पंक्ति पंक्तियों द्वारा एकल पंक्ति के बारे में जानकारी जोड़ा है। तालिका का MAX (आईडी) 3774 9 4 है, इसलिए मैंने अभी एक बड़ा बड़ा चुना है। मैंने 3774904 से नीचे एक आईडी के साथ ऐसा करने की कोशिश की लेकिन तालिका में नहीं था और इसी तरह के परिणाम मिल गए (तालिका में एक आईडी के लिए इसी तरह के परिणाम)। – nevets1219

+1

हाँ, 0.162 बनाम 0.452 * 0.452 के बाद से महत्वपूर्ण है 0.152 से लगभग 3 गुना लंबा है। यह विशेष रूप से दिलचस्प है कि व्याख्या से पता चलता है कि वे एक ही काम कर रहे हैं। मैं इसे postgresql टीम के साथ उठाऊंगा। [Pgsql-general] (http://www.postgresql.org/community/lists/) शायद एक अच्छी जगह –

उत्तर

5

ठीक है, पहली बात नोट करने के लिए है एसक्यूएल एक योजना में परिवर्तित करने के लिए किया है किसी तरह। आपके EXPLAIN परिणामों से पता चलता है कि यहां एक तर्क (आईएनएस) निर्माण की तुलना में समानता के लिए मूल रूप से भिन्न है।

WHERE id = 1; 

एक साधारण समानता फ़िल्टर में परिवर्तित हो गया है।

WHERE id IN (1); 

की एक सरणी मैच में तब्दील हो जाता:

WHERE id = ANY(ARRAY[1]); 

जाहिर योजनाकार सूचना के लिए है कि इन गणितीय समान हैं जहां एक सरणी ठीक एक सदस्य है बहुत चालाक नहीं है। तो यह क्या कर रहा है किसी भी आकार की सरणी के लिए योजना बना रहा है, यही कारण है कि आपको नेस्टेड लूप बिटमैप इंडेक्स स्कैन मिलता है।

यहां दिलचस्प क्या है कि यह धीमा नहीं है लेकिन अधिकांश प्रदर्शन के लिए यह प्रदर्शन बेहतर होता है। तो इन() खंड में एक सदस्य के साथ, यह 40 गुना धीमा है, और 10000 सदस्यों के साथ, यह केवल 170 गुना धीमा है, लेकिन इसका मतलब यह भी है कि 10000 सदस्य संस्करण 5000 तेज 10000 अलग इंडेक्स स्कैन से अधिक है आईडी पर

तो यहां क्या हो रहा है यह है कि योजनाकार एक ऐसी योजना का चयन कर रहा है जो बड़ी संख्या में आईडी की जांच की जाती है, लेकिन केवल कुछ ही होने पर अधिक खराब प्रदर्शन करती है।

+0

है, मैं सरणी आकार को बढ़ाने की कोशिश करूंगा और रिपोर्ट करता हूं कि क्या होता है! क्या बैच आकार चुनने के लिए सामान्य दिशानिर्देश हैं? – nevets1219

+0

लगता है कि हाइबरनेट को 50,000 पसंद नहीं आया (स्टैक ओवरफ़्लो त्रुटि दी गई) – nevets1219

+0

आपने जो लिखा है उसे दोबारा पढ़ें - मैंने 'जहां आईडी = 1' की कोशिश की, 'हम इसे ए कॉल करेंगे) और' आईडी आईडी (1); ' (हम इस बी को कॉल करेंगे) और बाद वाला धीमा है। यदि मैं ए को निष्पादित करते समय सही तरीके से समझ रहा हूं तो यह बी निष्पादित करने जैसा ही है लेकिन बी को निष्पादित करते समय, एक अलग योजना (आईडी की बड़ी सूची के पक्ष में) का उपयोग निष्पादन में किया जा सकता है (दूसरे शब्दों में बी बी के बराबर नहीं है)। मैंने ए और बी दोनों को निष्पादित किया है और वे एक ही योजना उत्पन्न करते हैं, शायद हाइबरनेट इसे कुछ कर रहा है? – nevets1219

4

यदि यहां समस्या वास्तव में उबलती है "मैं जितनी जल्दी हो सके रिकॉर्ड्स को हटा सकता हूं?" तो हटाएं ... IN() विधि प्रत्येक व्यक्तिगत पंक्ति के लिए हटाने के लिए बेहतर होने जा रही है, इसलिए कारणों का पीछा करना क्यों एक (?) एक सदस्य के साथ = से धीमा प्रतीत होता है? आपकी मदद नहीं करेगा।

यह उन सभी आईडी को पकड़ने के लिए एक अस्थायी तालिका के उपयोग की खोज करने लायक हो सकता है, जिसे आप हटाना चाहते हैं, फिर एक ही डिलीट चलाएं।

यदि यह बहुत महंगा नहीं है, तो यह व्यवस्था करना कि सूची में आईडी आरोही क्रम में हैं, बहुत बड़े डिलीट प्रदर्शन के लिए उपयोगी हो सकती है।अगर आपको उन्हें सॉर्ट करना है तो परेशान न करें, लेकिन अगर यह सुनिश्चित करने का कोई तरीका है कि प्रत्येक बैच को हटाए गए आईडी को इंडेक्स के उसी क्षेत्र में क्लस्टर किया गया है, तो यह थोड़ा फायदेमंद हो सकता है।

किसी भी मामले में, ऐसा लगता है अनुक्रमित किया जा रहा है और एक ही दोनों ही मामलों में उत्पन्न योजना मेरे लिए लग रहा है, तो मुझे आश्चर्य है कि वहाँ वास्तव में है एक क्वेरी पद व्याख्या और अनुकूलन यहां मुद्दा यह है, बल्कि हटाएं क्रिया के साथ ही एक मुद्दा से अगर । मुझे यह सुनिश्चित करने के लिए आंतरिकों के बारे में पर्याप्त जानकारी नहीं है कि मुझे डर है।

संबंधित मुद्दे