2015-01-12 12 views
12

पर निर्भर करता है मुझे लगता है कि मुझे लगता है कि ओरेकल में एक बग है, लेकिन मुझे आश्चर्य है कि कुछ दस्तावेज है जो मैंने याद किया है।क्या यह तालिका में शामिल होने पर ओरेकल में एक बग है जो तालिका

Fiddles: ओरेकल: http://sqlfiddle.com/#!4/43c19/2 एसक्यूएल सर्वर: http://sqlfiddle.com/#!3/ddc49/1 MySQL: http://sqlfiddle.com/#!2/43c195/1

मूल रूप से मैं एक मुख्य तालिका है कि मैं एक माध्यमिक मेज पर शामिल होने के छोड़ दिया है। तब मैं एक दृश्य में शामिल हो गया। यदि मैं इस दृश्य में शामिल होने में निर्दिष्ट करता हूं कि मैं केवल तब शामिल होना चाहता हूं जब द्वितीयक तालिका में कोई कॉलम शून्य न हो, मुझे अप्रत्याशित परिणाम मिलते हैं। यह सबसे अच्छा क्वेरी दिखा कर समझाया गया है:

SELECT 
    1, 
    MainTable.* 
FROM 
    MainTable 
    LEFT JOIN SecondaryTable ON MainTable.KeyColumn = SecondaryTable.KeyColumn 
    LEFT JOIN ViewWithoutSecondary ON ((SecondaryTable.KeyColumn IS NOT NULL) AND SecondaryTable.KeyColumn = ViewWithoutSecondary.KeyColumn) 
UNION ALL 
SELECT 
    2, 
    MainTable.* 
FROM 
    MainTable 
    LEFT JOIN SecondaryTable ON MainTable.KeyColumn = SecondaryTable.KeyColumn 
    LEFT JOIN ViewWithSecondary ON ((SecondaryTable.KeyColumn IS NOT NULL) AND SecondaryTable.KeyColumn = ViewWithSecondary.KeyColumn) 

निर्माण स्क्रिप्ट यह अपने आप को परीक्षण करने के लिए के लिए नीचे देखें। SQL सर्वर और MySQL में मुझे एक ही परिणाम मिलते हैं, हालांकि ओरेकल अलग है। स्कीमा में तीन टेबल और दो विचार हैं।

CREATE VIEW ViewWithoutSecondary 
AS 
SELECT 
    TertiaryTable.KeyColumn, 
    TertiaryValue + 1 ViewValue 
FROM 
    TertiaryTable 

CREATE VIEW ViewWithSecondary 
AS 
SELECT 
    SecondaryTable.KeyColumn, 
    TertiaryValue + 1 ViewValue 
FROM 
    SecondaryTable 
    LEFT JOIN TertiaryTable ON SecondaryTable.KeyColumn = TertiaryTable.KeyColumn; 

ओरेकल में, मैं पाया है कि अगर दृश्य SecondaryTable का संदर्भ होता है, तो मैं केवल MainTable से पंक्तियों माध्यमिक तालिका में एक मैच है कि मिलता है: इस प्रकार देखा गया परिभाषित कर रहे हैं। ऐसा लगता है कि ओरेकल दृश्य कोड को किसी भी तरह से रेखांकित कर रहा है ताकि पंक्तियों में से एक छोड़ी जा सके।

मुझे लगता है कि यदि मेनटेबल में तीन पंक्तियां हैं तो इसके दो बाएं जुड़ने से कम से कम तीन पंक्तियों को वापस लेना चाहिए, साथ ही साथ शामिल होने से कोई भी परिणाम। हालांकि उदाहरण में यह मामला नहीं है।

मुझे पता है कि SecondaryTable.KeyValue IS NOT NULL खंड के दूसरे भाग के बाद से अनावश्यक है क्योंकि मान शून्य है, लेकिन मैं एक बेहतर योजना के साथ अनुकूलक की मदद करने के लिए एक क्वेरी को फिर से करने की कोशिश कर रहा हूं।

उदाहरण चलाने के लिए पूर्ण निर्माण स्क्रिप्ट है:

CREATE TABLE MainTable 
(
    KeyColumn varchar(32), 
    ValueColumn varchar(32) 
); 

INSERT INTO MainTable VALUES ('123', 'abc'); 
INSERT INTO MainTable VALUES ('456', 'def'); 
INSERT INTO MainTable VALUES ('789', 'ghi'); 

CREATE TABLE SecondaryTable 
(
    KeyColumn varchar(32), 
    SecondaryValue integer 
); 

INSERT INTO SecondaryTable VALUES ('123', 1); 
INSERT INTO SecondaryTable VALUES ('456', 2); 

CREATE TABLE TertiaryTable 
(
    KeyColumn varchar(32), 
    TertiaryValue integer 
); 

INSERT INTO TertiaryTable VALUES ('123', 1); 

CREATE VIEW ViewWithoutSecondary 
AS 
SELECT 
    TertiaryTable.KeyColumn, 
    TertiaryValue + 1 ViewValue 
FROM 
    TertiaryTable; 

CREATE VIEW ViewWithSecondary 
AS 
SELECT 
    SecondaryTable.KeyColumn, 
    TertiaryValue + 1 ViewValue 
FROM 
    SecondaryTable 
    LEFT JOIN TertiaryTable ON SecondaryTable.KeyColumn = TertiaryTable.KeyColumn; 
+1

माइमर एसक्यूएल MySQL के समान परिणाम प्राप्त करता है। – jarlh

+0

तो डीबी इंजन क्या है: MySQL, SQL सर्वर या ओरेकल? आपके पास तीनों टैग हैं –

+0

मैं मानता हूं कि यह एक बग होना चाहिए। मैंने ओरेकल 10.2 के साथ कोशिश की और एक पंक्ति के साथ एक ही परिणाम मिला। MySQL और SQL सर्वर सही ढंग से काम करते हैं, ओरेकल नहीं करता है। –

उत्तर

1

आप एक प्रश्न पर योजना समझाने चलाते हैं, तो आप देख सकते हैं कि Oracle दृश्य इनलाइन करने से क्वेरी बदलाव ला रहा है, और किसी कारण से , यह बाएं-बाहरी के बजाए लाइन 2 पर एक आंतरिक जुड़ रहा है।

explain plan 
SET statement_id = 'no-hint' FOR 
SELECT 
    MainTable.* 
FROM 
    MainTable 
    LEFT JOIN SecondaryTable ON MainTable.KeyColumn = SecondaryTable.KeyColumn 
    LEFT JOIN ViewWithSecondary ON ((SecondaryTable.KeyColumn IS NOT NULL) AND SecondaryTable.KeyColumn = ViewWithSecondary.KeyColumn); 

SELECT PLAN_TABLE_OUTPUT 
    FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, 'no-hint','TYPICAL')); 


---------------------------------------------------------------------------------------- 
| Id | Operation    | Name   | Rows | Bytes | Cost (%CPU)| Time  | 
---------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |    |  2 | 108 | 20 (10)| 00:00:01 | 
| 1 | NESTED LOOPS OUTER |    |  2 | 108 | 20 (10)| 00:00:01 | 
|* 2 | HASH JOIN   |    |  2 | 108 |  7 (15)| 00:00:01 | 
| 3 | TABLE ACCESS FULL | SECONDARYTABLE |  2 | 36 |  3 (0)| 00:00:01 | 
| 4 | TABLE ACCESS FULL | MAINTABLE  |  3 | 108 |  3 (0)| 00:00:01 | 
| 5 | VIEW    |    |  1 |  |  7 (15)| 00:00:01 | 
|* 6 | FILTER    |    |  |  |   |   | 
|* 7 |  HASH JOIN OUTER |    |  1 | 36 |  7 (15)| 00:00:01 | 
|* 8 |  TABLE ACCESS FULL| SECONDARYTABLE |  1 | 18 |  3 (0)| 00:00:01 | 
| 9 |  TABLE ACCESS FULL| TERTIARYTABLE |  1 | 18 |  3 (0)| 00:00:01 | 
---------------------------------------------------------------------------------------- 

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

    2 - access("MAINTABLE"."KEYCOLUMN"="SECONDARYTABLE"."KEYCOLUMN") 
    6 - filter("SECONDARYTABLE"."KEYCOLUMN" IS NOT NULL) 
    7 - access("SECONDARYTABLE"."KEYCOLUMN"="TERTIARYTABLE"."KEYCOLUMN"(+)) 
    8 - filter("SECONDARYTABLE"."KEYCOLUMN"="SECONDARYTABLE"."KEYCOLUMN") 

एक काम के आसपास इस समस्या के लिए NO_MERGE संकेत का प्रयोग है।

SELECT /*+ NO_MERGE(ViewWithSecondary) */ 
    MainTable.* 
FROM 
    MainTable 
    LEFT JOIN SecondaryTable ON MainTable.KeyColumn = SecondaryTable.KeyColumn 
    LEFT JOIN ViewWithSecondary ON ((SecondaryTable.KeyColumn IS NOT NULL) AND SecondaryTable.KeyColumn = ViewWithSecondary.KeyColumn); 

यह उम्मीद परिणाम पैदा करता है:

KEYCOLUMN      VALUECOLUMN      
-------------------------------- -------------------------------- 
123        abc        
456        def        
789        ghi 

संकेत दिया क्वेरी के लिए क्वेरी योजना की तुलना करें। यहां हम लाइन 2 पर बाएं-बाहरी शामिल होते हैं।

explain plan 
SET statement_id = 'with-hint' FOR 
SELECT /*+ NO_MERGE(ViewWithSecondary) */ 
    MainTable.* 
FROM 
    MainTable 
    LEFT JOIN SecondaryTable ON MainTable.KeyColumn = SecondaryTable.KeyColumn 
    LEFT JOIN ViewWithSecondary ON ((SecondaryTable.KeyColumn IS NOT NULL) AND SecondaryTable.KeyColumn = ViewWithSecondary.KeyColumn); 

SELECT PLAN_TABLE_OUTPUT 
    FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, 'with-hint','TYPICAL')); 

-------------------------------------------------------------------------------------------- 
| Id | Operation    | Name    | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |     |  6 | 324 | 26 (8)| 00:00:01 | 
| 1 | NESTED LOOPS OUTER |     |  6 | 324 | 26 (8)| 00:00:01 | 
|* 2 | HASH JOIN OUTER  |     |  3 | 162 |  7 (15)| 00:00:01 | 
| 3 | TABLE ACCESS FULL | MAINTABLE   |  3 | 108 |  3 (0)| 00:00:01 | 
| 4 | TABLE ACCESS FULL | SECONDARYTABLE |  2 | 36 |  3 (0)| 00:00:01 | 
| 5 | VIEW     |     |  2 |  |  7 (15)| 00:00:01 | 
|* 6 | FILTER    |     |  |  |   |   | 
|* 7 |  VIEW    | VIEWWITHSECONDARY |  2 | 36 |  7 (15)| 00:00:01 | 
|* 8 |  HASH JOIN OUTER |     |  2 | 72 |  7 (15)| 00:00:01 | 
| 9 |  TABLE ACCESS FULL| SECONDARYTABLE |  2 | 36 |  3 (0)| 00:00:01 | 
| 10 |  TABLE ACCESS FULL| TERTIARYTABLE  |  1 | 18 |  3 (0)| 00:00:01 | 
-------------------------------------------------------------------------------------------- 

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

    2 - access("MAINTABLE"."KEYCOLUMN"="SECONDARYTABLE"."KEYCOLUMN"(+)) 
    6 - filter("SECONDARYTABLE"."KEYCOLUMN" IS NOT NULL) 
    7 - filter("SECONDARYTABLE"."KEYCOLUMN"="VIEWWITHSECONDARY"."KEYCOLUMN") 
    8 - access("SECONDARYTABLE"."KEYCOLUMN"="TERTIARYTABLE"."KEYCOLUMN"(+)) 
संबंधित मुद्दे