Странная проблема с функцией TO_NUMBER в Oracle - PullRequest
4 голосов
/ 07 мая 2010

У меня периодически возникала проблема при выполнении функции to_number в предложении where в столбце varchar2, если число записей превышает определенное число n. Я использовал, так как нет точного числа записей, по которым это происходит. На одной БД это происходит после того, как n было 1 миллион, на другой, когда он был 0,1. млн.

например. У меня есть таблица с 10 миллионами записей, скажем, Страна таблицы, в которой 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, но Google не помог мне в этом.

Кто-нибудь имеет представление об этой проблеме с функциями TO_NUMBER или oracle для больших данных?

Ответы [ 4 ]

5 голосов
/ 07 мая 2010

с полем 1 varchar2, содержащим числовые данные

Это не очень хорошая практика. Числовые данные должны храниться в столбцах NUMBER. Причина проста: если мы не обеспечим строгий тип данных, мы можем оказаться с нечисловыми данными в нашем столбце varchar2. Если это произойдет, то фильтр вроде этого

where to_number(field1) = 23 

потерпит неудачу с ORA-01722: invalid number.

Я не могу с уверенностью сказать, что именно это происходит в вашем сценарии, потому что я не понимаю, почему очевидно незначительные изменения в фильтрах идентификаторов изменили успешность запроса. Было бы поучительно посмотреть планы выполнения для разных версий запросов. Но я думаю, что это скорее проблема с вашими данными, чем ошибка в SGA.

3 голосов
/ 07 мая 2010

Предполагая, что вы знаете, что данный диапазон идентификаторов всегда будет приводить к тому, что field1 содержит числовые данные, вы можете сделать это вместо этого:

1 голос
/ 07 мая 2010

Предложите сделать следующее, чтобы точно определить, есть ли записи, содержащие нечисловые данные. Как уже говорили другие, изменения в плане выполнения и порядке оценки могут объяснить, почему ошибка не появляется постоянно.

(при условии 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>
0 голосов
/ 10 мая 2010

Рассмотрим написание функции 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
...