繁体   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