如果记录数超过某个数n,我在varchar2列的where子句中执行to_number函数时遇到了间歇性问题。我使用了n,因为它没有确切的记录数。在一个数据库上,当它为0.1时,n在另一个数据库上是100万。万美元。
E.g。我有一个包含1000万条记录的表,表示Table Country,其中field1 varchar2包含数字数据和Id
如果我以查询为例
select *
from country
where to_number(field1) = 23
and id >1 and id < 100000
这有效
但如果我进行查询
select *
from country
where to_number(field1) = 23
and id >1 and id < 100001
无法说出无效的号码
接下来我尝试查询
select *
from country
where to_number(field1) = 23
and id >2 and id < 100001
再次运作
由于我只收到无效号码,这令人困惑,但在日志文件中它说
Memory Notification: Library Cache Object loaded into SGA
Heap size 3823K exceeds notification threshold (2048K)
KGL object name :with sqlplan as (
select c006 object_owner, c007 object_type,c008 object_name
from htmldb_collections
where COLLECTION_NAME='HTMLDB_QUERY_PLAN'
and c007 in ('TABLE','INDEX','MATERIALIZED VIEW','INDEX (UNIQUE)')),
ws_schemas as(
select schema
from wwv_flow_company_schemas
where security_group_id = :flow_security_group_id),
t as(
select s.object_owner table_owner,s.object_name table_name,
d.OBJECT_ID
from sqlplan s,sys.dba_objects d
它似乎与SGA大小有关,但谷歌没有给我很多帮助。
对于大数据的TO_NUMBER或oracle函数,有没有人知道这个问题?
答案 0 :(得分:5)
其中包含field1 varchar2 数字数据
这不是好习惯。数字数据应保留在NUMBER列中。原因很简单:如果我们不强制执行强数据类型,我们可能会在varchar2列中发现非数字数据。如果发生这种情况,那么就像这样的过滤器
where to_number(field1) = 23
会因ORA-01722: invalid number
而失败。
我无法肯定地说这是您的场景中发生的事情,因为我不明白为什么ID过滤器中显然无关紧要的更改已经改变了查询的成功。查看不同版本查询的执行计划是有益的。但我认为,与SGA中的错误相比,您的数据更容易出现问题。
答案 1 :(得分:3)
假设您知道给定的id范围将始终导致包含数字数据的field1,您可以改为:
select *
from (
select /*+NO_MERGE*/ *
from country
where id >1 and id < 100000
)
where to_number(field1) = 23;
答案 2 :(得分:1)
建议执行以下操作以确定是否存在包含非数字数据的记录。正如其他人所说,执行计划和评估顺序的变化可以解释为什么错误不会始终如一。
(假设SQLPlus为客户端)
SET SERVEROUTPUT ON
DECLARE
x NUMBER;
BEGIN
FOR rec IN (SELECT id, field1 FROM country) LOOP
BEGIN
x := TO_NUMBER( rec.field1 );
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line( rec.id || ' ' || rec.field1 );
END;
END LOOP;
END;
/
原始问题的另一种解决方法是重写查询以避免隐式类型转换,例如。
SELECT id, TO_NUMBER( field1 )
FROM county
WHERE field1 = '23'
AND <whatever condition on id you want, if any>
答案 3 :(得分:0)
考虑编写一个IS_NUMBER PL / SQL函数:
CREATE OR REPLACE FUNCTION IS_NUMBER (p_input IN VARCHAR2) RETURN NUMBER
AS
BEGIN
RETURN TO_NUMBER (p_input);
EXCEPTION
WHEN OTHERS THEN RETURN NULL;
END IS_NUMBER;
/
SQL> SELECT COUNT(*) FROM DUAL WHERE IS_NUMBER ('TEST') IS NOT NULL;
COUNT(*)
----------
0
SQL> SELECT COUNT(*) FROM DUAL WHERE IS_NUMBER ('123.45') IS NOT NULL;
COUNT(*)
----------
1