2010-04-21 145 views
4

我有一個非常奇怪的問題,我有一個複雜的視圖,當我查詢特定列時返回不正確的數據。
下面有一個例如:oracle查詢結果不一致

select empname 
     , has_garnishment 
from timecard_v2 
where empname = 'Testerson, Testy'; 

此返回單個結果 'Testerson,暴躁', 'N'

但是,如果我使用查詢:

select empname 
     , has_garnishment 
from timecard_v2 
where empname = 'Testerson, Testy' 
and has_garnishment = 'Y'; 

此返回單結果'Testerson,Testy','Y'

第二個查詢應該返回第一個查詢的一個子集,但它返回一個不同的答案。

當我使用查詢:

select empname 
     , has_garnishment 
from timecard_v2 
where empname = 'Testerson, Testy' 
and has_garnishment = 'N'; 

我沒有得到任何結果

我已經解剖視圖,並確定視圖定義的這部分是哪裏出了問題產生和存在的問題,即使我把sql定義作爲一個直接查詢來運行(注意,爲了清楚起見,我刪除了除了感興趣部分外的所有select子句,在完整查詢中需要所有連接的表):


SELECT 
    e.fullname empname , 
    NVL2(ded.has_garn, 'Y', 'N') has_garnishment 
FROM timecard tc , 
    orderdetail od , 
    orderassign oa , 
    employee e , 
    employee3 e3 , 
    customer10 c10 , 
    order_misc om, 
    (SELECT COUNT(*) has_garn, 
    v_ssn 
    FROM deductions 
    WHERE yymmdd_stop        = 0 
    OR (LENGTH(yymmdd_stop)      = 7 
    AND to_date(SUBSTR(yymmdd_stop, 2), 'YYMMDD') > sysdate) 
    GROUP BY v_ssn 
) ded 
WHERE oa.lrn(+) = tc.lrn_order 
AND om.lrn(+) = od.lrn 
AND od.orderno = oa.orderno 
AND e.ssn  = tc.ssn 
AND c10.custno = tc.custno 
AND e.lrn  = e3.lrn 
AND e.ssn  = ded.v_ssn(+) 

關於'ded'子查詢的定義需要注意的一件事。 v_ssn字段是扣除表上的虛擬字段。

我不是軟件開發人員的DBA,但我們最近失去了我們的DBA,新的仍在加快速度,所以我試圖調試這個問題。這就是說,請解釋一些更徹底的東西,然後你會爲一位神諭專家。

謝謝

+1

DED子查詢似乎可以使用某些格式和註釋來幫助使其更易於支持。但我懷疑我的麻煩閱讀SQL與這個問題有任何關係。爲了獲得更多信息,請嘗試使用視圖SQL語句並添加「empname ='Testerson,Testy'」限制器。你會得到什麼結果? – Jay 2010-04-21 17:24:58

+1

我會感興趣的看到執行計劃的兩個查詢給出不一致的結果。在SQLPlus中,輸入'set autotrace traceonly explain',然後執行查詢。 – 2010-04-21 18:10:58

+1

我想知道當你輸入第一個含有had_garnishment ='N'的查詢時,你會得到什麼 – MJB 2010-04-21 19:31:04

回答

1

原來這個問題是一個矛盾的索引。該列中有一箇舊索引,即v_ssn虛擬列的構建。我放棄了該索引,查詢開始按預期行事。我仍然關心該索引如何影響查詢,但至少我的直接問題得到解決。

感謝您的幫助!

+2

那麼,v_ssn是基於一個非確定性函數?這是我能想到的唯一解釋,即刪除索引可能會改變查詢的結果。 – 2010-04-22 05:52:36

+0

你應該接受你自己的答案。 – APC 2010-04-22 07:08:16

0

首先,您有一個連接「AND od.orderno = oa.orderno」,它將取消「oa.lrn(+)= tc.lrn_order」上的外連接。 IE,如果tc.lrn_order沒有在oa上找到匹配,則外部聯接表示仍然返回一行,但是會有一個null orderno,這將與od無法匹配

其次,虛擬列的定義可能是相關的。如果刪除索引解決了問題,那麼它表明早期的計劃使用索引。

第三,ded子查詢看起來有點笨重。在表面上看,

SELECT COUNT(*) FROM tab WHERE COL=:val 

似乎非常相似

SELECT cnt FROM (SELECT COL, COUNT(*) FROM tab GROUP BY COL) WHERE COL=:val 

而且其中:VAL不「標籤」的存在,首先將返回0的計數和第二韓元」 t返回任何行(並且使用外連接,將返回NULL)。

如果在COL上有可用的索引,則選項1可能很有吸引力。我懷疑Oracle是在將前者重寫爲前者,而如果不是NVL2,而只是顯示了has_garn的值,那麼您會看到0而不是null。

了錯誤的另一種可能是這樣的:如果v_ssn基於FUNC(COL)

,那麼Oracle可能(錯誤地)假設FUNC(COL)必須爲空,如果COL爲null。如果大部分COL都爲空,則可能會假定在COL上使用索引來查找非空行會給它一個更小且更有效的一堆行來處理。