4

レコード数が特定の数nを超えると、varchar2列のwhere句でto_number関数を実行すると、断続的な問題が発生します。nを使用したのは、それが発生するレコードの正確な数がないためです。あるDBでは、nが0.1のときに別のDBで100万になった後に発生します。100万。

たとえば、1,000万件のレコードを含むテーブルがあり、数値データとIDを含むfield1varchar2があるTableCountryと言います。

例としてクエリを実行すると

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関数に関するこの問題について誰かが知っていますか?

4

4 に答える 4

5

数値データを含むfield1varchar2があります

これは良い習慣ではありません。数値データはNUMBER列に保持する必要があります。理由は単純です。強力なデータ型を適用しないと、varchar2列に数値以外のデータが含まれている可能性があります。それが起こった場合、このようなフィルター

where to_number(field1) = 23 

で失敗しORA-01722: invalid numberます。

IDのフィルターの明らかに重要でない変更がクエリの成功を変更した理由がわからないため、これがシナリオで起こっていることであるとは断言できません。さまざまなバージョンのクエリの実行プランを確認すると有益です。ただし、SGAのバグよりも、データの問題である可能性が高いと思います。

于 2010-05-06T23:16:18.387 に答える
3

指定された範囲のIDが常に数値データを含むfield1になることがわかっている場合は、代わりにこれを行うことができます。

select *
from (
  select /*+NO_MERGE*/ * 
  from country 
  where id >1 and id < 100000
)
where to_number(field1) = 23;
于 2010-05-07T01:41:20.040 に答える
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>
于 2010-05-07T13:24:46.610 に答える
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
于 2010-05-10T17:59:44.117 に答える