क्या एक पंक्ति को उसी मान के साथ अद्यतन करना वास्तव में पंक्ति को अद्यतन करता है?


28

मेरा प्रदर्शन-संबंधी प्रश्न है। मान लीजिए कि मेरा पहला नाम माइकल के साथ है। निम्नलिखित प्रश्न लें:

UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123

क्या क्वेरी वास्तव में अपडेट को निष्पादित करेगी, भले ही इसे उसी मूल्य पर अपडेट किया जा रहा हो? यदि हां, तो मैं इसे होने से कैसे रोकूं?


1
आप किसी कथन को क्यों निष्पादित करेंगे और साथ ही यह अपेक्षा करेंगे कि वह निष्पादित न हो?
मैक्स वर्नोन

@MaxVernon रूबी ऑन रेल्स ORM रिकॉर्ड को अपडेट नहीं करता है इसलिए मैं उत्सुक था अगर PostgreSQL ने ऐसा ही किया।
OneSneakyMofo

1
मैं सुझाव देता हूं कि अगर रूबी ऑन रेल्स कर रही है, तो यह शायद यह देखने के लिए कि क्या एक पंक्ति को अपडेट की आवश्यकता है, पहले एक चयन कर रहा है।
मैक्स वर्नोन

x को SO पर पोस्ट किया गया: stackoverflow.com/q/33156712/939860
Erwin Brandstetter

जवाबों:


35

Postgres के MVCC मॉडल के कारण , और एसक्यूएल के नियमों के अनुसार, प्रत्येक पंक्ति के UPDATEलिए एक नया पंक्ति संस्करण लिखता है जो खंड में बाहर नहीं किया जाता है।WHERE

यह करता है प्रदर्शन पर एक कम या ज्यादा उल्लेखनीय प्रभाव सीधे और परोक्ष रूप है। "खाली अपडेट" में किसी भी अन्य अपडेट की तरह प्रति पंक्ति लागत होती है। वे किसी भी अन्य अपडेट की तरह ट्रिगर्स (यदि मौजूद हैं) में आग लगाते हैं, तो उन्हें वाल-लॉग होना पड़ता है और वे टेबल को ब्लॉट करने वाली मृत पंक्तियों का उत्पादन करते हैं और VACUUMबाद में किसी भी अन्य अपडेट की तरह अधिक काम करते हैं ।

अनुक्रमणिका प्रविष्टियाँ और टोस्ट किए गए स्तंभ जहाँ शामिल किए गए किसी भी स्तंभ को नहीं बदला गया है , वही रह सकते हैं , लेकिन यह किसी भी अद्यतन पंक्ति के लिए सही है। सम्बंधित:

इस तरह के खाली अपडेट को बाहर करना लगभग एक अच्छा विचार है (जब वास्तविक मौका हो तो ऐसा हो सकता है)। आपने अपने प्रश्न में एक तालिका परिभाषा प्रदान नहीं की (जो हमेशा एक अच्छा विचार है)। हमें लगता है first_nameकि NULL हो सकता है (जो "पहले नाम" के लिए आश्चर्यजनक नहीं होगा), इसलिए क्वेरी को NULL-safe तुलना का उपयोग करना होगा :

UPDATE users
SET    first_name = 'Michael'
WHERE  id = 123
AND   first_name IS DISTINCT FROM 'Michael';

यदि first_name IS NULLअद्यतन करने से पहले, केवल first_name <> 'Michael'NULL का मूल्यांकन होगा और जैसे कि अद्यतन से पंक्ति को बाहर रखा जाएगा। डरपोक त्रुटि। यदि कॉलम परिभाषित किया गया हैNOT NULL , तो साधारण समानता की जांच करें, हालांकि, क्योंकि यह थोड़ा सस्ता है।

सम्बंधित:


1
Indexes entries and TOASTed columns where none of the involved columns are changed can stay the sameलेकिन क्या उन्हें पंक्ति के नए स्थान को इंगित करने के लिए अपडेट नहीं किया जाना चाहिए?
at

1
@dtgq: HOT अपडेट्स के साथ नहीं, जहाँ इंडेक्स पुराने स्थान की ओर इशारा कर सकता है, और ढेर टिशू को लाइव ट्यूपल प्राप्त करने के लिए HOT चेन को ट्रैस करना होगा। मैंने ऊपर और स्पष्टीकरण के लिए लिंक जोड़े।
इरविन ब्रान्डेसटेटर

1
MVCC के बारे में क्या एक नया अद्यतन लिखने के लिए एक noop अद्यतन के लिए कहता है?
jberryman

@jberryman: मुझे यकीन नहीं है। किसी भी तरह, कृपया अपने प्रश्न को नए प्रश्न के रूप में पूछें । आप संदर्भ के लिए इसे हमेशा लिंक कर सकते हैं। और आप वापस लिंक करने के लिए यहां एक टिप्पणी छोड़ सकते हैं (और मेरा ध्यान आकर्षित करें)।
एरविन ब्रान्डेसटेटर

2
@jberryman: मैं वास्तव में नहीं है पता वजहों परियोजना इस तरह से चला गया। यह बहुत पहले स्थापित किया गया था। लेकिन मुझे लगता है कि समानता के लिए हर पंक्ति की जाँच करना और अपरिवर्तित पंक्तियों के लिए एक अलग कोड-पथ होना अनावश्यक रूप से महंगा होगा। लेन-देन-आईडी की हैंडलिंग अधिक जटिल होगी - विशेष केसिंग rollback, स्नैपशॉट हैंडलिंग, लॉक मैनेजमेंट, वाल, क्या नहीं ...
इरविन ब्रान्डेसटेटर

4

ओआरएम की तरह रूबी ऑन रेल का प्रस्ताव आस्थगित निष्पादन है जो एक रिकॉर्ड को परिवर्तित (या नहीं) के रूप में चिह्नित करता है और फिर जब जरूरत होती है या बुलाया जाता है, तो डेटाबेस में परिवर्तन सबमिट करें।

PostgreSQL एक डेटाबेस है और ORM नहीं है। यदि एक नया मान आपकी क्वेरी में अद्यतित मान के समान था, तो यह जांचने में समय लगता है कि यह प्रदर्शन कम हो जाता।

इसलिए यह मान को अपडेट करेगा कि यह नए मूल्य के समान है या नहीं।

यदि आप इसे रोकना चाहते हैं, तो आप उसके जवाब में सुझाए गए मैक्स वर्नोन जैसे कोड का उपयोग कर सकते हैं।


2

आप बस whereखंड में जोड़ सकते हैं :

UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
    AND (first_name <> 'Michael' OR first_name IS NULL);

यदि first_nameके रूप में परिभाषित किया गया है NOT NULL, तो OR first_name IS NULLभाग को हटाया जा सकता है।

शर्त:

(first_name <> 'Michael' OR first_name IS NULL)

(एर्विन के उत्तर में) और भी सुरुचिपूर्ण ढंग से लिखा जा सकता है:

first_name IS DISTINCT FROM 'Michael'

यह जानते हुए भी नहीं कि स्तंभ NULL हो सकता है, जो एक डरपोक बग का परिचय दे सकता है।
इरविन ब्रान्डसेट्टर

1
@ErwinBrandstetter मैं उत्तर अपडेट कर रहा था - तब मैंने टिप्पणी और आपका उत्तर देखा!
ypercube y

एडिट के लिए धन्यवाद, @ypercube - और NULL@erwin के बारे में टिप्पणी के लिए
Max Vernon

1

डेटाबेस बिंदु से

आपके प्रश्न का उत्तर है - हां। अद्यतन जगह ले जाएगा। डेटाबेस पिछले मूल्य की जांच नहीं करता है, यह केवल नए मूल्य को निर्धारित करता है।

जैसा कि मेमोरी में होता है (और केवल एक कमिट जारी होने के बाद डेटाफाइल्स को लिखा जाएगा) प्रदर्शन एक मुद्दा नहीं होगा।

ORM के दृष्टिकोण से

आम तौर पर आपके पास डेटाबेस की एकल पंक्ति का प्रतिनिधित्व करने वाला एक ऑब्जेक्ट होगा (यह उससे बहुत अधिक जटिल हो सकता है, लेकिन चलो इसे सरल रखें)। यह ऑब्जेक्ट मेमोरी (ऐप सर्वर स्तर पर) में प्रबंधित किया जाता है और उस ऑब्जेक्ट का केवल नवीनतम कमिटेड संस्करण वास्तव में एक निश्चित बिंदु पर डेटाबेस में बना देगा।

यह अलग व्यवहार की व्याख्या कर सकता है।

अब, एक 3 डी प्रिंटर के साथ एक कार्गो जहाज की तुलना न करें। तथ्य यह है कि आप कार्गो जहाजों का उपयोग करके 3 डी प्रिंटर भेज सकते हैं इसका मतलब यह नहीं है कि उनके बीच किसी भी तरह की तुलना हो सकती है।

का आनंद लें!

मुझे आशा है कि इसने कुछ अवधारणाओं को स्पष्ट किया है।


4
प्रदर्शन है और इस मुद्दे को। हर अपडेट को डिस्क (लॉग और टेबल) पर लिखना होता है।
ypercube y

यह आपके द्वारा उपयोग किए जाने वाले वास्तविक RDBMS पर निर्भर करेगा। लेकिन उनमें से ज्यादातर हर एक अपडेट नहीं करते हैं, लेकिन केवल आखिरी कमिटेड ब्लॉक है जो उनके पास मेमोरी में है। आप एक डेटाबेस में कभी भी एक पंक्ति नहीं पढ़ते या लिखते हैं। आप ब्लॉकों को पढ़ते / लिखते हैं और उन्हें तब तक याद में रखते हैं जब तक आपको एक ही स्थान पर एक नया ब्लॉक डालने के लिए इसे बाहर नहीं निकालना है। स्मृति में रहते हुए, पंक्ति में प्रत्येक परिवर्तन डिस्क पर नहीं लिखा जाएगा, लेकिन केवल ब्लॉक सामग्री जब "डेटाबेस लेखक" प्रक्रिया को उस मेमोरी ब्लॉक को डेटाफाइल में डंप करने के लिए संकेत दिया जाता है। तो, नहीं ... कोई समस्या नहीं है जब तक कि आपका आवेदन ब्लॉक को बहुत लंबे समय के लिए रद्द न कर दे।
सिलवरियन

1
यह सवाल पोस्टग्रेज के बारे में है, किसी मनमाने डीबीएमएस के बारे में नहीं। और जबकि अपडेट सभी को एक-एक करके लिखना नहीं पड़ता है, डेटाबेस पर हर लिखना लॉग में लिखना होता है। यदि कोई परिवर्तन लगातार भंडारण पर नहीं लिखा जाता है, तो DBMS सिस्टम क्रैश से कैसे बचेगा?
ypercube y

हाँ, यह लॉग में लिखता है, मेमोरी के साथ-साथ चौकियों के दौरान भी। जब तक आपके पास समवर्ती उपयोगकर्ताओं की एक बड़ी संख्या नहीं है, तब तक यह समस्या नहीं होनी चाहिए। लॉग बैचों में भी लिखे गए हैं। मुझे लगता है कि हम सर्वर के बारे में बात कर रहे हैं। यदि आप 5400RPM HDD वाले लैपटॉप में पोस्टग्रेज डेटाबेस के बारे में बात कर रहे हैं, तो हाँ ... आपके पास हमेशा प्रदर्शन समस्याएँ होंगी। तो, अंतिम उत्तर पहले वाला होगा ... यह बहुत सी चीजों पर निर्भर करता है।
सिलवरियन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.