[英]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.