簡體   English   中英

Oracle SQL Where條件將varchar2字段與數字或字符串進行比較

[英]Oracle SQL Where Condition comparing varchar2 field with number or string

我有兩個帶有以下各列的表:

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有200,000條記錄,表2有500,000條記錄

我有以下簡單的聯接:

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')

如果來自表1的每個BATCH_NUM為'400012'並且表2中的所有ID都匹配,則該計數的預期結果應為500,000。

當我在Oracle(v11或v10)中運行這些查詢時,SQL#2似乎花了很長時間,而且我不得不在10到15分鍾后停止運行查詢。 SQL#1和#3似乎在不到一秒鍾的時間內立即返回了全部500,000條記錄的結果。 起初,我認為這是一個索引問題,但是添加索引並不能解決該問題。 我在TOAD和SQL Developer中嘗試了此查詢,結果相同。

我在這里不知所措,因為表1中的BATCH_NUM列是VARCHAR2,並且您認為數據類型的隱式轉換會導致查詢變慢,而不是未轉換的比較快。 有人可以解釋嗎?

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

可以肯定到底發生了什么,請執行以下操作:

explain plan for
select ......
/

然后,立即執行以下操作:

select * from table(dbms_xplan.display);

並發布結果。

如果不看執行計划,我所說的只是猜測。

哦,請發布表中存在的所有索引的定義。

-標記

我想您可能陷入了這樣的陷阱:索引訪問=快速,全表掃描=慢。

過時的統計信息可能會導致不良的執行時間。

您可以使用以下方法檢查過時的統計信息:

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;

如果必須進行從數字到字符串的類型轉換,則不能使用該列上的“普通”索引。 因此,如果您查看第二個查詢的解釋計划,則可能會看到以條件to_string(batch_num)=='400012'進行的全表掃描。

如果確實必須能夠對字符串進行限定,則可以為該列創建基於函數的index [1]。 如果可以使用選項1或3中描述的語法,則可以在batch_num列上利用“普通”索引。

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

好,在與同事坐下來查看解釋計划並查看索引之后,我們終於找到了問題。 我要感謝Mark Bobak和Kevin Burton在此方面的投入。 這是我們發現的:

有一個以BATCH_NUM和其他兩列為主索引的索引。 進行強制轉換時,Oracle決定對子表中與父表中的BATCH_NUM和ID匹配的所有Table1_ID進行全表掃描。 在這種情況下,進行全表掃描相對較快。 否,使用BATCH_NUM作為字符串的搜索條件-這是索引失敗並導致整個查詢“掛起”的地方。 由於BATCH_NUM在任何方面都不是唯一的,因此沒有任何隱式或顯式轉換的條件將導致Oracle嘗試使用該索引,並且說明計划表明它嘗試對索引進行全范圍掃描(如果表是大約500,000到1,000,000行的記錄)。 刪除索引實際上有助於解決此問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM