2011-10-12 246 views
2

我有兩個表有以下欄目:的Oracle SQL Where條件VARCHAR2場比較數字或字符串

Table1 
{ ID   NUMBER(15), 
    ROLL_NUM  VARCHAR2(9), 
    BATCH_NUM  VARCHAR2(6), 
    ACCT_BALANCE NUMBER(15,2) 
} 

Table2 
{ Table1_ID  NUMBER(15) REFERENCES TABLE1.ID, 
    SEQ_NUM  NUMBER(2), 
    TRANS_NUM  VARCHAR2(10), 
    TRANS_AMT  NUMBER(8,2), 
    TRANS_DT  DATE 
} 

表1已經有20萬次的記錄和表2有500000條記錄

我有簡單連接,如下所示:

SQL#1:

SELECT A.ROLL_NUM, A.ACCT_BALANCE, B.TRANS_NUM, TRANS_AMT, TRANS_DT 
FROM TABLE1 A, TABLE2 B 
WHERE B.Table1_ID = A.ID 
AND A.BATCH_NUM = 400012 

SQL#2:

SELECT A.ROLL_NUM, A.ACCT_BALANCE, B.TRANS_NUM, TRANS_AMT, TRANS_DT 
FROM TABLE1 A, TABLE2 B 
WHERE B.Table1_ID = A.ID 
AND A.BATCH_NUM = '400012' 

SQL#3:

SELECT A.ROLL_NUM, A.ACCT_BALANCE, B.TRANS_NUM, TRANS_AMT, TRANS_DT 
FROM TABLE1 A, TABLE2 B 
WHERE B.Table1_ID = A.ID 
AND A.BATCH_NUM = TO_NUMBER('400012') 

從計數預期的結果應該在50萬,如果從表1的每BATCH_NUM是「400012」,所有的ID的比賽了表2中。

當我在Oracle(v11或v10)中運行這些查詢時,SQL#2似乎需要永久使用,並且我必須在10到15分鐘後停止運行查詢。 SQL#1和#3似乎在不到一秒的時間內即刻帶回500,000條記錄的結果。起初,我認爲這是一個索引問題,但添加索引不會解決問題。我在TOAD和SQL Developer中嘗試了這個查詢,獲得了相同的結果。

因爲Table1中的BATCH_NUM列是VARCHAR2,所以我覺得很遺憾,您會認爲數據類型的隱式轉換會導致查詢速度變慢,而不會比未轉換的比較速度更快。有人可以解釋這個嗎?

+0

您能否發佈三個查詢的解釋計劃結果嗎? – Ollie

回答

4

我同意使用隱式轉換會阻止索引訪問路徑。

可以肯定什麼是真正上,執行以下操作:

explain plan for 
select ...... 
/

然後,緊隨其後的是,這樣做:

select * from table(dbms_xplan.display); 

和後的結果。

沒有看執行計劃,我說的任何事情都是猜測。

哦,請張貼表格中所有索引的定義。

馬克

1

我猜你就掉進認爲索引訪問=快, 全表掃描=緩慢的陷阱。

過期的統計數據可能會導致您的執行時間不一致。

您可以檢查使用陳舊的數據:

DECLARE 
    l_objlist DBMS_STATS.objecttab; 
BEGIN 
    DBMS_STATS.gather_schema_stats (ownname  => USER, 
            options  => 'LIST STALE', 
            objlist  => l_objlist 
           ); 

    FOR i IN 1 .. l_objlist.COUNT 
    LOOP 
     DBMS_OUTPUT.put_line ( l_objlist (i).objtype 
          || ' .. ' 
          || l_objlist (i).objname 
          ); 
    END LOOP; 
END; 
0

OK,坐下來與同事看解釋計劃來看,在指標後,我們終於發現了問題。我想感謝Mark Bobak和Kevin Burton對此的投入。這裏是我們發現的:

有一個索引有BATCH_NUM和另外兩列作爲主索引。當存在轉換轉換時,Oracle決定對子表中與BATCH_NUM和ID匹配的所有Table1_ID執行全表掃描。在這種情況下進行全表掃描相對較快。不,BATCH_NUM作爲字符串的搜索條件 - 這是索引失敗並導致整個查詢「掛起」的地方。由於BATCH_NUM不以任何方式唯一,因此沒有任何隱式或顯式轉換的情況會導致Oracle嘗試並使用索引,並且解釋計劃顯示它試圖對索引執行全範圍掃描(如果表格大約有500,000到1,000,000行記錄)。刪除索引實際上有助於解決此問題。

0

如果必須進行從數字到字符串的類型轉換,則不能使用列上的「正常」索引。因此,如果您查看第二個查詢的解釋計劃,則可能會看到全表掃描發生的資格爲to_string(batch_num)=='400012'。

如果您確實必須能夠限定字符串,則可以爲該列創建基於函數的索引[1]。如果您可以使用選項1或3中描述的語法,則可以在batch_num列上使用「正常」索引。

[1] - http://docs.oracle.com/cd/E11882_01/appdev.112/e25518/adfns_indexes.htm