2012-07-12 13 views
7

क्या आप इस वाक्यांश को समझने में मेरी मदद कर सकते हैं?ओरेकल: थोक संग्रह प्रदर्शन

थोक बाँध के बिना, PL/SQL प्रत्येक रिकॉर्ड है कि, डाला अद्यतन, या संदर्भ स्विच है कि प्रदर्शन को चोट करने के लिए अग्रणी हटा दी जाती है के लिए एसक्यूएल इंजन करने के लिए एक SQL विवरण भेजता है।

उत्तर

17

ओरेकल के भीतर, एसक्यूएल वर्चुअल मशीन (वीएम) और पीएल/एसक्यूएल वीएम के माध्यम से पीएल/एसक्यूएल इंजन का उपयोग करता है। जब आपको एक वीएम से दूसरे वीएम में स्थानांतरित करने की आवश्यकता होती है, तो आपको एक संदर्भ शिफ्ट की लागत लगती है। व्यक्तिगत रूप से, उन संदर्भ परिवर्तन अपेक्षाकृत तेज़ होते हैं, लेकिन जब आप पंक्ति-दर-पंक्ति प्रसंस्करण कर रहे होते हैं, तो वे आपके कोड के खर्च के एक महत्वपूर्ण अंश के लिए खाते में जोड़ सकते हैं। जब आप थोक बाइंड का उपयोग करते हैं, तो आप एक वीएम से डेटा की कई पंक्तियों को एक संदर्भ में बदलते हैं, जिससे संदर्भ परिवर्तनों की संख्या में काफी कमी आती है, जिससे आपका कोड तेज़ी से बढ़ जाता है।

उदाहरण के लिए, एक स्पष्ट कर्सर लें। यदि मैं यह

DECLARE 
    CURSOR c 
     IS SELECT * 
      FROM source_table; 
    l_rec source_table%rowtype; 
BEGIN 
    OPEN c; 
    LOOP 
    FETCH c INTO l_rec; 
    EXIT WHEN c%notfound; 

    INSERT INTO dest_table(col1, col2, ... , colN) 
     VALUES(l_rec.col1, l_rec.col2, ... , l_rec.colN); 
    END LOOP; 
END; 

की तरह कुछ लिखने तो हर बार जब मैं लाने पर अमल, मैं

  • हूँ एसक्यूएल वीएम
  • लिए PL/SQL वीएम से एक संदर्भ पारी एसक्यूएल वीएम पूछ प्रदर्शन कर्सर निष्पादित करने के लिए डेटा के अपने एकल पंक्ति वापस जाने के लिए डेटा
  • PL/SQL वी एम के लिए एसक्यूएल वीएम से दूसरे संदर्भ पारी प्रदर्शन वापस की अगली पंक्ति उत्पन्न करने के लिए

और हर बार जब मैं एक पंक्ति डालता हूं, तो मैं वही कर रहा हूं। मैं पीएल/एसक्यूएल वीएम से एसक्यूएल वीएम में डेटा की एक पंक्ति को शिप करने के लिए एक संदर्भ शिफ्ट की लागत का खर्च कर रहा हूं, एसक्यूएल को INSERT कथन निष्पादित करने के लिए कह रहा है, और उसके बाद पीएल/एसक्यूएल पर एक और संदर्भ शिफ्ट की लागत लगाना।

यदि source_table में 1 मिलियन पंक्तियां हैं, तो यह 4 मिलियन संदर्भ बदलाव है जो संभवतः मेरे कोड के विलुप्त समय के उचित अंश के लिए जिम्मेदार होगा। यदि, दूसरी तरफ, मैं BULK COLLECT को 100 के LIMIT के साथ करता हूं, तो मैं पीएल/एसक्यूएल में संग्रह में एसक्यूएल वीएम से डेटा की 100 पंक्तियों को पुनर्प्राप्त करके अपने संदर्भ परिवर्तनों का 99% समाप्त कर सकता हूं, हर बार जब मैं लागत लेता हूं एक संदर्भ शिफ्ट और प्रत्येक बार जब मैं एक संदर्भ शिफ्ट लेता हूं, गंतव्य तालिका में 100 पंक्तियां डालता हूं।

मेरे कोड को फिर से लिखने कर सकते हैं हर बार जब मैं लाने पर अमल थोक संचालन

DECLARE 
    CURSOR c 
     IS SELECT * 
      FROM source_table; 
    TYPE nt_type IS TABLE OF source_table%rowtype; 
    l_arr nt_type; 
BEGIN 
    OPEN c; 
    LOOP 
    FETCH c BULK COLLECT INTO l_arr LIMIT 100; 
    EXIT WHEN l_arr.count = 0; 

    FORALL i IN 1 .. l_arr.count 
     INSERT INTO dest_table(col1, col2, ... , colN) 
     VALUES(l_arr(i).col1, l_arr(i).col2, ... , l_arr(i).colN); 
    END LOOP; 
END; 

का उपयोग करना अब, मैं संदर्भ बदलाव का एक सेट के साथ मेरे संग्रह में डेटा की अधिकतम 100 पंक्तियां पुनः प्राप्त। और हर बार जब मैं अपना FORALL सम्मिलित करता हूं, तो मैं संदर्भ पंक्तियों के एक सेट के साथ 100 पंक्तियां डाल रहा हूं। यदि source_table में 1 मिलियन पंक्तियां हैं, तो इसका मतलब है कि मैं 4 मिलियन संदर्भ बदलावों से 40,000 संदर्भ परिवर्तनों में गया हूं। यदि संदर्भ परिवर्तनों के लिए जिम्मेदार ठहराया गया है, तो मेरे कोड के विलुप्त समय का 20%, मैंने बीत चुके समय के 1 9 .8% को समाप्त कर दिया है।

संदर्भ परिवर्तनों की संख्या को और कम करने के लिए आप LIMIT के आकार को बढ़ा सकते हैं लेकिन आप जल्दी से कम रिटर्न के कानून को दबाते हैं। यदि आपने 100 के बजाय 1000 के LIMIT का उपयोग किया है, तो आप 99% की बजाय संदर्भ परिवर्तनों का 99.9% खत्म कर देंगे। इसका मतलब यह होगा कि आपका संग्रह 10x अधिक पीजीए मेमोरी का उपयोग कर रहा था, हालांकि। और यह हमारे hypothetical उदाहरण में केवल 0.18% अधिक समय बीत जाएगा। आप बहुत जल्दी उस बिंदु तक पहुंचते हैं जहां अतिरिक्त मेमोरी आप अतिरिक्त संदर्भ बदलावों को समाप्त करके सहेजने से अधिक समय जोड़ती है। आम तौर पर, LIMIT कहीं 100 से 1000 के बीच मीठा स्थान होने की संभावना है।

बेशक

, इस उदाहरण में, यह और अधिक कुशल अभी भी सभी संदर्भ बदलाव को खत्म करने और एक एकल एसक्यूएल बयान

INSERT INTO dest_table(col1, col2, ... , colN) 
    SELECT col1, col2, ... , colN 
    FROM source_table; 

यह केवल मतलब होगा में PL/SQL का सहारा लेना में सब कुछ करना होगा पहली जगह यदि आप स्रोत तालिका से डेटा के किसी प्रकार का हेरफेर कर रहे हैं जिसे आप SQL में उचित रूप से कार्यान्वित नहीं कर सकते हैं।

इसके अतिरिक्त, मैंने जानबूझकर मेरे उदाहरण में एक स्पष्ट कर्सर का उपयोग किया। यदि आप ओरेकल के हाल के संस्करणों में अंतर्निहित कर्सर का उपयोग कर रहे हैं, तो आपको 10012 के LIMIT के साथ BULK COLLECT का लाभ मिलता है। एक और स्टैक ओवरफ्लो प्रश्न है जो रिश्तेदार performance benefits of implicit and explicit cursors with bulk operations पर चर्चा करता है जो उन विशेष झुर्रियों के बारे में अधिक जानकारी देता है।

1

जैसा कि मैं इसे समझता हूं, इसमें दो इंजन शामिल हैं, PL/SQL engine and SQL Engine

INSERT INTO t VALUES(1) 

एसक्यूएल इंजन द्वारा संसाधित किया जाता है, जबकि

FOR Lcntr IN 1..20 

    END LOOP 

पी एल द्वारा निष्पादित किया जाता है: एक प्रश्न है कि एक समय में एक इंजन का उपयोग दो

उदाहरण के बीच स्विच करने की तुलना में अधिक कुशल है निष्पादित/एसक्यूएल इंजन

यदि आप ऊपर दिए गए दो कथन को जोड़ते हैं, लूप में INSERT डालते हैं,

FOR Lcntr IN 1..20 
    INSERT INTO t VALUES(1) 
END LOOP 

ओरेकल प्रत्येक (20) पुनरावृत्तियों के लिए दो इंजनों के बीच स्विचिंग करेगा। इस मामले में बल्क इंसर्ट की अनुशंसा की जाती है जो निष्पादन

+0

आपकी आखिरी वाक्य थोड़ी सी धोखा दे रही है। बल्क संदर्भ स्विच केवल एक बार होता है, हालांकि यह अभी भी होता है। – viper

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