2012-06-05 14 views
6

मुझे एक SELECT कथन के भीतर उपयोगकर्ता द्वारा परिभाषित कार्यों का उपयोग करने के साथ कुछ दिलचस्प व्यवहार का अनुभव हो रहा है।ओरेकल में किसी क्वेरी में उपयोगकर्ता परिभाषित फ़ंक्शंस का मूल्यांकन कब किया जाता है?

मेरे पास कुछ संग्रहित प्रक्रियाएं हैं जो एक ही तालिका से डेटा को पढ़ और साफ़ करती हैं। इन संग्रहीत प्रक्रियाओं का उपयोग कई स्रोतों द्वारा किया जाता है।

मेरी टिप्पणियों में, ऐसा लगता है कि उपयोगकर्ता परिभाषित कार्यों कभी कभी मनमाने ढंग से, नहीं हमेशा तुरंत मूल्यांकन किया जाता है के बाद या। SELECT कथन का निष्पादन है कि यह प्रयोग किया जाता है

उदाहरण के लिए के दौरान, एक संग्रहीत प्रक्रिया में, मैं एक का चयन करें बयान कुछ इस तरह लग सकता है है:

SELECT Something, MyFunction(Something) FROM Somewhere; 

यह एक और संग्रहीत प्रक्रिया के लिए एक कॉल, जो तालिका से डेटा को मिटा देता है द्वारा पीछा किया। शुद्ध डेटा की मात्रा किसी अन्य तालिका द्वारा शासित होती है, जो अधिकतम आईडी पढ़ती है। ऐसा इसलिए है कि एक शुद्ध को किसी भी डेटा को मिटाना नहीं चाहिए जिसे संग्रहीत प्रक्रिया निष्पादन के किसी अन्य उदाहरण द्वारा अभी तक नहीं पढ़ा गया है।

मेरे परीक्षण कोड में, MyFunction बस कहीं भी तालिका में पंक्तियों की संख्या देता है। इस प्रकार, मैं कल्पना करता हूं कि यह हमेशा पंक्तियों की संख्या के बराबर होना चाहिए जो SELECT कथन लौटाता है। हालांकि, ऐसे मामलों में जहां मैं इस संग्रहीत प्रक्रिया के दो उदाहरणों को चलाने में, मैं इस तरह के परिणाम कुछ पाने:

पहले क्वेरी उदाहरण:

Something MyFunction(Something) 
--------- --------------------- 
A   3 
B   3 
C   3 

दूसरा क्वेरी उदाहरण:

Something MyFunction(Something) 
--------- --------------------- 
A   0 
B   0 
C   0  

ऐसा क्यों है कि दूसरी क्वेरी सभी पंक्तियों को लौटाती है, लेकिन उपयोगकर्ता परिभाषित फ़ंक्शन जो उसी तालिका पर चलता है रिपोर्ट करता है कि तालिका में कोई और पंक्ति नहीं है?

क्या वैसे भी मैं यह सुनिश्चित कर सकता हूं कि दूसरा क्वेरी उदाहरण सुसंगत है कि उपयोगकर्ता परिभाषित फ़ंक्शंस अभी भी वही डेटा देखता है जो अभिभावक संग्रहीत प्रक्रिया देख रहा है?

+0

मुझे समझ में नहीं आ रहा है: 2 कॉल के बीच y कहां टेबल शुद्ध करें? – Sebas

+0

भ्रम के बारे में क्षमा करें। स्पष्टीकरण के लिए, एक संग्रहीत प्रक्रिया है जो (1) चयन कथन निष्पादित करती है, और (2) चयन कथन के बाद शुद्ध प्रक्रिया को कॉल करती है। – acee

+0

मैं देखता हूं, इसलिए फ़ंक्शन सही परिणाम देता है ना? चयन नहीं करता है, या अलग-अलग कहा जाता है कि कोई पंक्ति वापस नहीं की जानी चाहिए। की पुष्टि? – Sebas

उत्तर

9

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

व्यावहारिक दृष्टि से, इसका मतलब है कि कुछ

तरह
SELECT something, 
     COUNT(*) OVER() 
    FROM table_name 

(यदि क्वेरी 3 पंक्तियों रिटर्न 3) हमेशा सही उत्तर वापस आ जाएगी, यदि आप एक समारोह में बिल्कुल एक ही तर्क डाल

कि SQL विवरण

SELECT something, 
     count_table_name 
    FROM table_name 

जरूरी वें एक मूल्य नहीं लौटेगा मैचों में तालिका में पंक्तियों की संख्या (और न ही यह आवश्यक रूप से प्रत्येक पंक्ति के लिए एक ही परिणाम लौटाएगा)। यदि आप अपने फ़ंक्शन में देरी करते हैं तो आप कार्रवाई में देख सकते हैं ताकि आप एक अलग सत्र में डेटा को संशोधित कर सकें।उदाहरण

SQL> create table foo(col1 number); 

Table created. 

SQL> insert into foo select level from dual connect by level <= 3; 

3 rows created. 

के लिए एक समारोह है कि प्रत्येक पंक्ति में एक 10 सेकंड की देरी

SQL> ed 
Wrote file afiedt.buf 

    1 create or replace function fn_count_foo 
    2 return number 
    3 is 
    4 l_cnt integer; 
    5 begin 
    6 select count(*) 
    7  into l_cnt 
    8  from foo; 
    9 dbms_lock.sleep(10); 
10 return l_cnt; 
11* end; 
12/

Function created. 

अब कहते हैं, अगर सत्र 1 में, मैं बयान

select col1, fn_count_foo 
    from foo; 

तो सत्र पर स्विच शुरू बनाएं 2 जहां मैं एक नई पंक्ति

SQL> insert into foo values(4); 

1 row created. 

SQL> commit; 

Commit complete. 

आप देख सकते हैं कि समारोह तथ्य यह है कि SQL विवरण में ही केवल आपके सत्र उपयोग serializable लेनदेन अलगाव स्तर होने से 3 पंक्तियों

SQL> select col1, fn_count_foo 
    2 from foo; 

     COL1 FN_COUNT_FOO 
---------- ------------ 
     1   3 
     2   4 
     3   4 

आपको लगता है कि समस्या से बच सकते हैं देखता है के बावजूद दूसरा निष्पादन के दौरान नव प्रतिबद्ध पंक्ति देखता है एसक्यूएल कथन निष्पादित करने से पहले। तो, उदाहरण के लिए,

सत्र 1 में, serializable के लिए लेन-देन अलगाव स्तर सेट और क्वेरी

SQL> set transaction isolation level serializable; 

Transaction set. 

SQL> select col1, fn_count_foo 
    2 from foo; 

सत्र 2 में शुरू करते हैं, एक नई पंक्ति

SQL> insert into foo values(5); 

1 row created. 

SQL> commit; 

Commit complete. 

और जब सत्र 1 सम्मिलित 40 सेकंड बाद लौटाता है, सबकुछ सुसंगत है

SQL> select col1, fn_count_foo 
    2 from foo; 

     COL1 FN_COUNT_FOO 
---------- ------------ 
     1   4 
     2   4 
     3   4 
     4   4 
+0

आह, नोट्स के लिए धन्यवाद। संग्रहीत प्रक्रिया के संदर्भ में मैं इसे ठीक से कैसे ठीक से सेट करूं? प्रक्रिया को किसी अन्य एप्लिकेशन द्वारा बुलाया जा रहा है। – acee

+0

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

+0

+1 अच्छा स्पष्टीकरण जस्टिन। मैं सिर्फ ओआरए -0877 (इस लेनदेन के लिए उपयोग को क्रमबद्ध नहीं कर सकता) त्रुटि से सावधान रहना चाहता हूं, उदाहरण के लिए, यदि सत्र 2 अपडेट (और करता है) एक पंक्ति के दौरान सत्र 1 अपनी लंबी क्वेरी चला रहा है, और बाद में सत्र 1 उसी पंक्ति को अद्यतन करने का प्रयास करता है। मुझे लगता है कि मेरा मुद्दा यह है कि अधिकांश लोगों को इसका इस्तेमाल डिफ़ॉल्ट रूप से पढ़ने के अलगाव से निपटने के लिए किया जाता है। – tbone

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

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