2016-08-12 12 views
8

मैं सिर्फ कैसे Oracle में NULL 'अप्रत्याशित' व्यवहार को जन्म दे सकता समझाने के लिए एक उदाहरण बनाने की कोशिश कर रहा था, लेकिन मैं कुछ मैं उम्मीद नहीं थी पाया है ...ओरेकल - टेबल उर्फ ​​और शून्य मूल्यांकन में शामिल होने में

स्थापना:

SQL> select * from tabNull T1 inner join tabNull T2 using(val); 

VAL  DESCR    DESCR 
---------- -------------------- -------------------- 
A   ONE CHAR    ONE CHAR 

अगर मैं मेज उपनाम हटाने के लिए, मैं:

create table tabNull (val varchar2(10), descr varchar2(100)); 
insert into tabNull values (null, 'NULL VALUE'); 
insert into tabNull values ('A', 'ONE CHAR'); 

यह मेरी अपेक्षा देता

SQL> select * from tabNull inner join tabNull using(val); 

VAL  DESCR    DESCR 
---------- -------------------- -------------------- 
A   ONE CHAR    ONE CHAR 
A   ONE CHAR    ONE CHAR 

और यह मेरे लिए काफी आश्चर्यजनक है।

दो प्रश्नों के लिए निष्पादन योजनाओं में एक कारण पाया जा सकता है; तालिका उपनाम के साथ, ओरेकल एक HASH शामिल हों करता है और फिर T1.val = T2.val लिए जाँच करता है:

------------------------------------------------------------------------------ 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT |   |  1 | 118 |  7 (15)| 00:00:01 | 
|* 1 | HASH JOIN   |   |  1 | 118 |  7 (15)| 00:00:01 | 
| 2 | TABLE ACCESS FULL| TABNULL |  2 | 118 |  3 (0)| 00:00:01 | 
| 3 | TABLE ACCESS FULL| TABNULL |  2 | 118 |  3 (0)| 00:00:01 | 
------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - access("T1"."VAL"="T2"."VAL") 
उपनाम बिना

, यह पहली फिल्टर एक रिक्त नहीं मूल्यों के लिए मेज की घटना है, इस प्रकार केवल एक पंक्ति उठा, और फिर इसे एक कार्तीय बनाता है दूसरी घटना के साथ, इस प्रकार दो पंक्तियां दे रही हैं; भले ही यह सही है, मैं एक कार्टशियन के परिणाम की अपेक्षा करता हूं, लेकिन मेरे पास DESCR = 'NULL VALUE' के साथ कोई पंक्ति नहीं है।

-------------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |   |  2 | 118 |  6 (0)| 00:00:01 | 
| 1 | MERGE JOIN CARTESIAN|   |  2 | 118 |  6 (0)| 00:00:01 | 
|* 2 | TABLE ACCESS FULL | TABNULL |  1 | 59 |  3 (0)| 00:00:01 | 
| 3 | BUFFER SORT  |   |  2 |  |  3 (0)| 00:00:01 | 
| 4 | TABLE ACCESS FULL | TABNULL |  2 |  |  3 (0)| 00:00:01 | 
-------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - filter("TABNULL"."VAL" IS NOT NULL) 

क्या यह किसी भी तरह सही/अपेक्षित है? वापस पंक्तियों की संख्या की तुलना में कार्टेशियन का परिणाम भी अजनबी नहीं है? क्या मैं योजनाओं को गलत समझ रहा हूं, या इतना बड़ा लापता हूं कि मैं नहीं देख सकता?

+0

मैं आमतौर पर "उपयोग" कीवर्ड का उपयोग नहीं करता, तो क्या होता है यदि आप इसके बजाय कीवर्ड पर उपयोग करते हैं? – Nick

+0

चालू होने पर मुझे "कॉलम अस्पष्ट रूप से परिभाषित" से बचने के लिए कॉलम उपनाम का उपयोग करना होगा, इसलिए कोई प्रश्न नहीं; वही बात अगर मैं पुराने जॉइन सिंटैक्स – Aleksej

+0

का उपयोग करता हूं तो दूसरा परिणाम सही नहीं है। –

उत्तर

1

http://docs.oracle.com/javadb/10.10.1.2/ref/rrefsqljusing.html using(val) के अनुसार ON tabnull.val=tabnull.val के रूप में यहाँ तब्दील हो तो

select tabNull.*, tabNull.descr from tabNull inner join tabNull 
on tabNull.val = tabNull.val; 

अगला एक योजना ओरेकल हर सदस्य शामिल हों लेकिन में किसी भी स्थान पर दूसरी अन्य नाम का उपयोग करने के लिए कोई कारण नहीं देखता के लिए चाहिए [लगभग] विभिन्न उपनाम आवंटित निर्माण करने के लिए चुनें और चालू करें। तो

select t1.*, t1.descr from tabNull t1 inner join tabNull t2 
on t1.val = t1.val; 

योजना

--------------------------------------------------------------------------------       
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  |       
--------------------------------------------------------------------------------       
| 0 | SELECT STATEMENT  |   |  2 | 28 |  4 (0)| 00:00:01 |       
| 1 | MERGE JOIN CARTESIAN|   |  2 | 28 |  4 (0)| 00:00:01 |       
|* 2 | TABLE ACCESS FULL | TABNULL |  1 | 14 |  2 (0)| 00:00:01 |       
| 3 | BUFFER SORT  |   |  2 |  |  2 (0)| 00:00:01 |       
| 4 | TABLE ACCESS FULL | TABNULL |  2 |  |  2 (0)| 00:00:01 |       
--------------------------------------------------------------------------------       


Predicate Information (identified by operation id):              
---------------------------------------------------              

    2 - filter("T1"."VAL" IS NOT NULL)  
+0

यह सही समझ में आता है, लेकिन मेरा मानना ​​है कि यह एक्सप्लाइन प्लान एलेक्स द्वारा पोस्ट किया गया है। यह ऑब्जेक्ट का नाम दोनों बार TABNULL के रूप में दिखाता है। यह विभिन्न उपनामों को निर्दिष्ट अनुकूलक की तरह नहीं दिखता है। – mathguy

+0

मैं देखता हूं। मैं मान सकता हूं कि 'वर्चुअल' उपनामों की तरह - यह योजना है कि इस तरह के उपनाम थे। दूसरे शब्दों में, यह सभी मूल्यों को लेता है, चेक केवल पहली घटना से भविष्यवाणी करता है, और दूसरे का उपयोग मेर्ज जॉइन कार्टिसियन के रूप में किया जाता है। – Serg

+0

फिर से, मुझे नहीं लगता कि यह मामला है; जब आप सबक्वायरीज़ का उपयोग करते हैं, यदि आप उन्हें कोई नाम नहीं देते हैं, तो ऑप्टिमाइज़र उन्हें अपठनीय (मनुष्यों के लिए) नाम देगा जो एक्स्पलाइन प्लान में दिखाई देंगे, इसलिए मुझे लगता है कि यह वही होगा यदि यह वास्तव में वर्चुअल एलियास को असाइन करता है इस आत्म-सम्मिलन में तालिका। – mathguy

0

संपादित: मैं नीचे कि वाक्य रचना गैर कानूनी है का कहना है कि; आगे विचार पर, यह मेरे हिस्से पर बीएस है, मुझे नहीं पता कि एक तथ्य के लिए (मैं इस बात पर ध्यान नहीं दे सकता कि भाषा परिभाषा उपनामों में स्वयं-शामिल होने के लिए आवश्यक है)। मुझे अभी भी विश्वास है कि नीचे दी गई व्याख्या शायद सही है, चाहे वह "बग" या "अपरिभाषित व्यवहार" के लिए है, मैं नीचे उल्लेख करता हूं।

*

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

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

ठीक है, वैसे भी, क्या आप देख रहे हैं के लिए कोई स्पष्टीकरण है?मेरा मानना ​​है कि यह वास्तव में एक कार्टेशियन शामिल है, और निक के सुझाव के रूप में एक संघ नहीं है।

चलो खुद को अनुकूलक के जूते में डाल दें। यह FROM सूची में पहली तालिका देखता है, यह इसे स्कैन करता है, अब तक इतना अच्छा है।

तो यह दूसरी तालिका पढ़ता है, और इसे इस तरह कॉलम की एक सूची है:

tabNULL.val, tabNULL.descr, tabNULL.val, tabNULL.descr

में शामिल होने हालत tabNULL.val = tabNULL.val

अनुकूलक गूंगा है, यह है अच्छा नहीं है। यह आपके विपरीत, इस बिंदु पर महसूस नहीं करता है कि tabNULL तालिका के दो अलग-अलग अवतारों के लिए खड़ा है। यह मानता है कि समीकरण के दोनों किनारों पर tabNULL.val समान मूल्य हैं और वे दोनों तालिका के पहले "अवतार" को संदर्भित करते हैं। एकमात्र मामला जब विफल रहता है तो tabNULL.val शून्य है, इसलिए यह tabNULL.val IS NOT NULL बनने वाले खंड के साथ क्वेरी को दोहराता है।

केवल पहली तालिका tabNULL.val IS NOT NULL के लिए चेक की गई है; ऑप्टिमाइज़र सूची में फिर से दिखाई नहीं देता है tabNULL.val सूची में दिखाई देता है और इसका एक अलग अर्थ हो सकता है! फिर शामिल होता है; इस बिंदु पर कोई और शर्त नहीं छोड़ी गई है, इसलिए तालिका के दूसरे अवतार में दोनों पंक्तियों में पहली तालिका से A, ONE CHAR के लिए शामिल होने वाली पंक्तियां उत्पन्न होंगी।

फिर, प्रक्षेपण में, फिर केवल पहले tabNULL.val को पढ़ा जाएगा और आउटपुट में दोनों कॉलम पॉप्युलेट करेगा। आप पूछताछ इंजन से मूल्य tabNULL.val दो बार वापस करने के लिए कहते हैं, और आपके दिमाग में यह विभिन्न स्थानों से है, लेकिन tabNULL.val लेबल वाला केवल एक स्मृति स्थान है, और यह पहली तालिका से क्या स्टोर करता है।

बेशक, बहुत कम जानते हैं कि ऑप्टिमाइज़र और क्वेरी इंजन क्या करता है, लेकिन इस मामले में मुझे लगता है कि यह एक बहुत सुरक्षित अनुमान है।

+1

यदि वाक्यविन्यास अवैध है, तो ओरेकल में एक वाक्यविन्यास त्रुटि की रिपोर्ट न करने में एक बग है। लेकिन तथ्य यह है कि समस्या के वाक्यविन्यास से कोई लेना देना नहीं है और यह मेरे लिए एक बग प्रतीत होता है। –

+0

आप सही हो सकते हैं - जिस चीज को मैं निश्चित रूप से नहीं जानता (मैं वास्तव में इसे दस्तावेज़ीकरण में नहीं देख सकता) यह है कि यदि स्वयं-शामिल वाक्यविन्यास को उपनाम की आवश्यकता होती है (यदि वह वास्तव में भाषा परिभाषा में लिखा गया है)। फिर भी, या तो "बग" या "सिंटैक्स का उल्लंघन होने पर अपरिभाषित व्यवहार" के स्पष्टीकरण के रूप में, मुझे लगता है कि मेरा जवाब समझ में आता है। क्या आप उस पर एक राय है? धन्यवाद! – mathguy

0

USING कीवर्ड मेरे लिए नया है, लेकिन जो मैंने पढ़ा है उसके अनुसार यह एसक्यूएल में सिंटैक्स में शामिल होने का एक नया तरीका है। (Oracle USING Keyword देखें)

select * from tabNull T1 inner join tabNull T2 using(val);
के बराबर है:
select * from tabNull inner join tabNull on tabNull.val = tabNull.val;

समस्या यह है कि दूसरे प्रश्न में में तालिका नामों में शामिल होने है:
select * from tabNull T1 inner join tabNull T2 on T1.val = T2.val;

select * from tabNull inner join tabNull using(val);
के बराबर है tabNull.val = tabNull.val अद्वितीय नहीं हैं।

यह खराब वाक्यविन्यास है जो पारंपरिक त्रुटि सिंटैक्स का उपयोग किया गया था, तो एक त्रुटि हुई होगी।

मेरे सबसे अच्छा अनुमान है कि ओरेकल (जो सभी पंक्तियों दोगुनी) दो तालिकाओं पर एक पूर्ण पार उत्पाद का प्रदर्शन किया है, और फिर समाप्त हो nulls क्योंकि USING equijoins का उपयोग करना चाहिए (यानी, के बराबर है "=") और null 'isn है टी कुछ भी बराबर है।

0

क्षमा करें, मुझे नहीं लगता कि यह वास्तव में एक उत्तर है।यह ज्यादातर सिर्फ एक टिप्पणी/यह करने के लिए अपनी पोस्टिंग में उत्तर है:

कार्तीय लौटे पंक्तियों की संख्या से भी अजनबी का परिणाम मूल्य नहीं है?

एक योजना का हर कदम एक "प्रक्षेपण" उस कॉलम/भाव है कि कदम से उत्पादन कर रहे हैं की सूची है। क्या हो रहा है कि समान उपनाम ओरेकल के प्रक्षेपण को गठबंधन कर रहा है जो कि दो स्तंभों को केवल एक कॉलम में पेश किया जाना चाहिए।

यह अगर आप अपने उदाहरण में दो अलग-अलग तालिकाओं का उपयोग और विशिष्ट नाम कॉलम की एक जोड़ी जोड़ने को देखने के लिए क्या हो रहा है देखने के लिए, इस तरह आसान है:

create table tabNull1 (val varchar2(10), descr varchar2(100), t1_real_descr varchar2(100)); 
insert into tabNull1 values (null, 'T1-NULL VALUE', 'T1-NULL VALUE'); 
insert into tabNull1 values ('A', 'T1-ONE CHAR', 'T1-ONE CHAR'); 


create table tabNull2 (val varchar2(10), descr varchar2(100), t2_real_descr varchar2(100)); 
insert into tabNull2 values (null, 'T2-NULL VALUE', 'T2-NULL VALUE'); 
insert into tabNull2 values ('A', 'T2-ONE CHAR', 'T2-ONE CHAR'); 

select * from tabNull1 t inner join tabNull2 t using(val); 

VAL DESCR   T1_REAL_DESCR  DESCR_1  T2_REAL_DESCR                       
------ ---------------- ----------------- ------------- ----------------- 
A  T2-ONE CHAR  T1-NULL VALUE  T2-ONE CHAR T2-ONE CHAR 
A  T2-ONE CHAR  T1-ONE CHAR  T2-ONE CHAR T2-ONE CHAR 

आप देख सकते हैं, अपने सिद्धांत कार्टेशियन जॉइन के बारे में सही था।

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