Oracle
 sql >> डेटाबेस >  >> RDS >> Oracle

Oracle:बल्क कलेक्ट प्रदर्शन

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

उदाहरण के लिए, एक स्पष्ट कर्सर लें। अगर मैं ऐसा कुछ लिखता हूं

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;

फिर हर बार जब मैं फ़ेच को निष्पादित करता हूं, तो मैं हूं

  • पीएल/एसक्यूएल वीएम से एसक्यूएल वीएम में संदर्भ बदलाव करना
  • डेटा की अगली पंक्ति उत्पन्न करने के लिए SQL VM को कर्सर निष्पादित करने के लिए कहना
  • डेटा की मेरी एकल पंक्ति वापस करने के लिए SQL VM से वापस PL/SQL VM में एक और संदर्भ बदलाव करना

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

अगर source_table 1 मिलियन पंक्तियाँ हैं, यह 4 मिलियन संदर्भ बदलाव हैं जो संभवतः मेरे कोड के बीता हुआ समय के एक उचित अंश के लिए जिम्मेदार होंगे। अगर, दूसरी ओर, मैं एक BULK COLLECT do करता हूं LIMIT . के साथ 100 में से, मैं 100 पंक्तियों को पीएल/एसक्यूएल में संग्रह में एसक्यूएल वीएम से डेटा की 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% के लिए जिम्मेदार हैं, तो मैंने बीते हुए समय का 19.8% समाप्त कर दिया है।

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

बेशक, इस उदाहरण में, सभी संदर्भ बदलावों को समाप्त करना और एक ही SQL कथन में सब कुछ करना अभी भी अधिक कुशल होगा

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

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

इसके अतिरिक्त, मैंने जानबूझकर अपने उदाहरण में एक स्पष्ट कर्सर का उपयोग किया। यदि आप निहित कर्सर का उपयोग कर रहे हैं, तो Oracle के हाल के संस्करणों में, आपको BULK COLLECT का लाभ मिलता है। LIMIT . के साथ 100 का अप्रत्यक्ष रूप से। एक और स्टैक ओवरफ्लो प्रश्न है जो थोक संचालन के साथ निहित और स्पष्ट कर्सर के सापेक्ष प्रदर्शन लाभों पर चर्चा करता है जो उन विशेष झुर्रियों के बारे में अधिक विस्तार से बताता है।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. (+) =ऑरैकल एसक्यूएल में ऑपरेटर जहां क्लॉज

  2. बिना ब्राउज़र के Oracle फॉर्म को स्टैंडअलोन के रूप में चलाएं

  3. Oracle D2k फॉर्म 6i . में एक फॉर्म स्क्रीन को रिफ्रेश / अपडेट करना

  4. एक कर्सर को सशर्त रूप से परिभाषित करें

  5. क्या आप Oracle के साथ Microsoft Entity Framework का उपयोग कर सकते हैं?