यह हाल ही में SO और PostgreSQL मेलिंग सूचियों दोनों पर कई बार सामने आया है।
TL;DR आपके अंतिम दो बिंदुओं के लिए:
(ए) बड़ा साझा_बफर हो सकता है कि सीआई सर्वर पर TRUNCATE धीमा क्यों है। भिन्न fsync कॉन्फ़िगरेशन या SSDs के बजाय घूर्णी मीडिया का उपयोग भी दोष में हो सकता है।
(बी) TRUNCATE
एक निश्चित लागत है, लेकिन जरूरी नहीं कि DELETE
. से धीमी हो , साथ ही यह अधिक काम करता है। विस्तृत विवरण देखें जो इस प्रकार है।
अपडेट करें: इस पोस्ट से pgsql-प्रदर्शन पर एक महत्वपूर्ण चर्चा हुई। यह धागा देखें।
अद्यतन 2: 9.2beta3 में सुधार जोड़े गए हैं जिससे इसमें मदद मिलनी चाहिए, इस पोस्ट को देखें।
TRUNCATE
. की विस्तृत व्याख्या बनाम DELETE FROM
:
जबकि इस विषय का विशेषज्ञ नहीं है, मेरी समझ यह है कि TRUNCATE
प्रति टेबल लगभग एक निश्चित लागत है, जबकि DELETE
n पंक्तियों के लिए कम से कम O(n) है; इससे भी बदतर अगर तालिका को हटाने के संदर्भ में कोई विदेशी कुंजी है।
मैंने हमेशा यह मान लिया था कि एक TRUNCATE
. की निश्चित लागत DELETE
. की लागत से कम था करीब-करीब खाली टेबल पर, लेकिन यह बिल्कुल भी सच नहीं है।
TRUNCATE table;
DELETE FROM table;
. से अधिक करता है
TRUNCATE table
. के बाद डेटाबेस की स्थिति बहुत कुछ वैसा ही है जैसे आप दौड़ना चाहते हैं:
DELETE FROM table;
VACCUUM (FULL, ANALYZE) table;
(9.0+ केवल, फुटनोट देखें)
... बेशक TRUNCATE
वास्तव में DELETE
. के साथ इसके प्रभावों को प्राप्त नहीं करता है और एक VACUUM
।
मुद्दा यह है कि DELETE
और TRUNCATE
अलग-अलग काम करें, इसलिए आप समान परिणामों वाले दो आदेशों की तुलना नहीं कर रहे हैं।
ए DELETE FROM table;
मृत पंक्तियों और ब्लोट को रहने की अनुमति देता है, अनुक्रमणिका को मृत प्रविष्टियां ले जाने की अनुमति देता है, क्वेरी प्लानर द्वारा उपयोग किए गए तालिका आंकड़ों को अपडेट नहीं करता है, आदि।
एक TRUNCATE
आपको एक पूरी तरह से नई तालिका और अनुक्रमणिका देता है जैसे कि वे केवल CREATE
. थे ईडी। यह ऐसा है जैसे आपने सभी रिकॉर्ड हटा दिए, तालिका को फिर से अनुक्रमित किया और VACUUM FULL
किया ।
अगर आपको इस बात की परवाह नहीं है कि टेबल में क्रूड बचा है क्योंकि आप जाने वाले हैं और इसे फिर से भरने वाले हैं, तो बेहतर होगा कि आप DELETE FROM table;
का उपयोग करें। .
क्योंकि आप VACUUM
नहीं चला रहे हैं आप पाएंगे कि मृत पंक्तियाँ और अनुक्रमणिका प्रविष्टियाँ ब्लोट के रूप में जमा हो जाती हैं जिन्हें स्कैन किया जाना चाहिए और फिर अनदेखा किया जाना चाहिए; यह आपके सभी प्रश्नों को धीमा कर देता है। यदि आपके परीक्षण वास्तव में इतना सारा डेटा नहीं बनाते और हटाते हैं जिसे आप नोटिस या परवाह नहीं कर सकते हैं, और आप हमेशा एक VACUUM
कर सकते हैं या यदि आप करते हैं तो अपने टेस्ट रन के माध्यम से दो भाग। बेहतर होगा, आक्रामक ऑटोवैक्यूम सेटिंग्स को यह सुनिश्चित करने दें कि ऑटोवैक्यूम यह आपके लिए पृष्ठभूमि में करता है।
आप अभी भी TRUNCATE
. कर सकते हैं संपूर्ण . के बाद आपके सभी टेबल परीक्षण सूट यह सुनिश्चित करने के लिए चलता है कि कई रनों में कोई प्रभाव नहीं बनता है। 9.0 और नए पर, VACUUM (FULL, ANALYZE);
टेबल पर विश्व स्तर पर कम से कम उतना ही अच्छा है जितना बेहतर नहीं है, और यह बहुत आसान है।
IIRC Pg में कुछ अनुकूलन हैं, जिसका अर्थ है कि यह तब नोटिस कर सकता है जब आपका लेन-देन केवल एक ही है जो तालिका को देख सकता है और वैसे भी ब्लॉक को तुरंत चिह्नित कर सकता है। परीक्षण में, जब मैं ब्लोट बनाना चाहता था तो मुझे इसे करने के लिए एक से अधिक समवर्ती कनेक्शन रखना पड़ता था। हालांकि, मैं इस पर भरोसा नहीं करूंगा।
DELETE FROM table;
बिना f/k refs वाली छोटी तालिकाओं के लिए बहुत सस्ता है
DELETE
के लिए बिना किसी विदेशी कुंजी संदर्भ वाली तालिका से सभी रिकॉर्ड, सभी पीजी को अनुक्रमिक तालिका स्कैन करना होगा और xmax
सेट करना होगा टुपल्स का सामना करना पड़ा। यह एक बहुत ही सस्ता ऑपरेशन है - मूल रूप से एक लीनियर रीड और एक सेमी-लीनियर राइट। AFAIK इसे इंडेक्स को छूना नहीं है; वे तब तक डेड टुपल्स की ओर इशारा करते रहते हैं जब तक कि वे बाद में VACUUM
से साफ नहीं हो जाते यह तालिका में ब्लॉक को भी चिह्नित करता है जिसमें केवल मृत टुपल्स मुक्त होते हैं।
DELETE
केवल तभी महंगा हो जाता है जब बहुत सारे . हों रिकॉर्ड्स की संख्या, यदि बहुत सारे विदेशी कुंजी संदर्भ हैं जिनकी जांच की जानी चाहिए, या यदि आप बाद की VACUUM (FULL, ANALYZE) table;
TRUNCATE
. से मेल खाने की जरूरत है आपके DELETE
. की लागत के भीतर के प्रभाव ।
यहां मेरे परीक्षणों में, एक DELETE FROM table;
आमतौर पर TRUNCATE
. से 4 गुना तेज था 0.5ms बनाम 2ms पर। यह एक SSD पर एक परीक्षण DB है, जो fsync=off
. के साथ चल रहा है क्योंकि अगर मैं यह सारा डेटा खो दूं तो मुझे परवाह नहीं है। बेशक, DELETE FROM table;
सभी समान कार्य नहीं कर रहा है, और यदि मैं VACUUM (FULL, ANALYZE) table;
यह बहुत अधिक महंगा 21ms है, इसलिए DELETE
केवल एक जीत है अगर मुझे वास्तव में टेबल प्रिस्टिन की आवश्यकता नहीं है।
TRUNCATE table;
DELETE
. की तुलना में बहुत अधिक निश्चित लागत का काम और हाउसकीपिंग करता है
इसके विपरीत, एक TRUNCATE
बहुत काम करना पड़ता है। इसे तालिका के लिए नई फ़ाइलें आवंटित करनी चाहिए, इसकी टोस्ट तालिका यदि कोई हो, और तालिका में प्रत्येक अनुक्रमणिका है। हेडर उन फाइलों में लिखे जाने चाहिए और सिस्टम कैटलॉग को भी अपडेट करने की आवश्यकता हो सकती है (उस बिंदु पर सुनिश्चित नहीं है, चेक नहीं किया गया है)। इसके बाद इसे पुरानी फाइलों को नए के साथ बदलना होगा या पुराने को हटाना होगा, और यह सुनिश्चित करना होगा कि फाइल सिस्टम ने सिंक्रोनाइज़ेशन ऑपरेशन - fsync () या इसी तरह के परिवर्तनों के साथ पकड़ा है - जो आमतौर पर डिस्क पर सभी बफ़र्स को फ्लश करता है। . यदि आप (डेटा-खाने) विकल्प fsync=off
के साथ चल रहे हैं, तो मुझे यकीन नहीं है कि सिंक को छोड़ दिया गया है या नहीं ।
मुझे हाल ही में पता चला कि TRUNCATE
पुरानी तालिका से संबंधित सभी PostgreSQL के बफ़र्स को भी फ्लश करना चाहिए। विशाल shared_buffers
. के साथ इसमें बहुत कम समय लग सकता है . मुझे संदेह है कि यही कारण है कि यह आपके सीआई सर्वर पर धीमा है।
शेष राशि
वैसे भी, आप देख सकते हैं कि एक TRUNCATE
एक तालिका जिसमें एक संबद्ध TOAST तालिका है (अधिकांश करते हैं) और कई अनुक्रमणिका में कुछ क्षण लग सकते हैं। लंबे समय तक नहीं, लेकिन DELETE
. से अधिक लंबा करीब-करीब खाली टेबल से।
नतीजतन, आप DELETE FROM table;
. करने से बेहतर हो सकते हैं ।
--
नोट:9.0 से पहले DBs पर, CLUSTER table_id_seq ON table; ANALYZE table;
या VACUUM FULL ANALYZE table; REINDEX table;
TRUNCATE
. के अधिक निकट होगा . VACUUM FULL
impl 9.0 में बहुत बेहतर में बदल गया।