7

作業中のOracleインスタンスから奇妙な動作が発生します。これはItanium上の11gR1であり、RACはなく、特別なものはありません。最終的には、データウェアハウスのシナリオで、あるOracleインスタンスから別のインスタンスにデータを移動します。

DBリンク上で実行されている半複雑なビューがあります。大規模なテーブルに対する4つの内部結合と、中規模のテーブルに対する5つの左側の結合。

問題は次のとおりです。SQLDeveloper(またはSQL * Plus)でビューをテストすると、問題はなく、重複はまったくありません。ただし、実際にビューを使用してデータをテーブルに挿入すると、多数の重複が発生します。

編集:-データは空のテーブルに入ります。クエリ内のすべてのテーブルはデータベースリンク上にあります。クエリに渡されるのは日付だけです(たとえば、INSERT INTO target SELECT * FROM view WHERE view.datecol = dQueryDate)-

ビューのPKでパーティション化されたROW_NUMBER()関数をselectステートメントに追加してみました。すべての行は1として番号が付けられて戻ってきます。ただし、挿入として実行された同じステートメントは、以前と同じ重複を生成し、現在は便利な番号が付けられています。重複した行の数は、キーごとに同じではありません。一部のレコードは4回存在し、一部は1回だけ存在します。

私はこれが行動に非常に当惑していると思います。:) SETテーブル(一意の行のみ)とMULTISETテーブル(重複行が許可されている)があるTeradataでの作業を思い出させますが、Oracleにはそのような機能はありません。

行をクライアントに返すselectは、それらの行を別の場所に挿入するselectと同じように動作する必要があります。これが起こる正当な理由を想像することはできませんが、おそらく私は想像力の失敗に苦しんでいます。;)

他の誰かがこれを経験したのか、それともこのプラットフォームのバグなのかしら。

解決

@Garyのおかげで、「EXPLAIN PLAN FOR {my query};」を使用して、この問題を解決することができました。および「SELECT*FROM TABLE(dbms_xplan.display);」。実際にINSERTに使用される説明は、SELECTとは大きく異なります。

SELECTの場合、ほとんどのプラン操作は「INDEXROWIDによるTABLEACCESS」および「INDEXUNIQUESCAN」です。'Predicate Information'ブロックには、クエリからのすべての結合とフィルターが含まれています。最後に「注-完全にリモートステートメント」と表示されます。

INSERTの場合、インデックスへの参照はありません。「述語情報」ブロックはわずか3行で、新しい「リモートSQL」ブロックには9つの小さなSQLステートメントが表示されます。

データベースは私のクエリを9つのサブクエリに分割し、それらをローカルで結合しようとします。小さい方の選択を実行することで、重複のソースを見つけました。

これは、リモートリンクに関するOracleコンパイラのバグだと思います。SQLを書き直すときに論理的な欠陥が発生します。基本的に、コンパイラはWHERE句を適切に適用していません。私はちょうどそれをテストしていて、持ち帰るための5つのキーのINリストを与えました。SELECTは5行を戻します。INSERTは、77,000以上の行をターゲットに配置し、INリストを完全に無視します。

{正しい動作を強制する方法をまだ探していますが、開発の観点からは理想的ではありませんが、リモートデータベースにビューを作成するように依頼する必要があるかもしれません。動作するようになったら編集します…}

4

9 に答える 9

6

Oracleのバグのようです。次の回避策が見つかりました。「」を「insert into select ...」のように機能させたい場合select ...は、選択をサブ選択にパックできます。

例えば ​​:

select x,y,z from table1, table2, where ...

->重複なし

insert into example_table
select x,y,z from table1, table2, where ...

->重複エラー

insert into example_table
select * from (
       select x,y,z from table1, table2, where ...
)

->重複なし

よろしく

于 2013-04-11T07:42:36.520 に答える
3

頭に浮かぶことの1つは、通常、SELECTのオプティマイザープランはFIRST_ROWSプランを優先して行を呼び出し元に早期に返すことですが、INSERT ... SELECTはALL_ROWSプランを優先して、完全なデータセット。DBMS_XPLAN.DISPLAY_CURSORを使用して(V $ SQLのsql_idを使用して)クエリプランを確認します。

DBリンク上で実行されている半複雑なビューがあります。大規模なテーブルに対する4つの内部結合と、中規模のテーブルに対する5つの左側の結合。...クエリ内のすべてのテーブルがデータベースリンク上にあります

繰り返しますが、潜在的な問題点です。SELECT内のすべてのテーブルがDBリンクのもう一方の端にある場合、クエリ全体がリモートデータベースに送信され、結果セットが返されます。INSERTをスローすると、ローカルデータベースがクエリを処理し、子テーブルからすべてのデータをプルする可能性が高くなります。ただし、ビューがローカルデータベースで定義されているかリモートデータベースで定義されているかによって異なります。後者の場合、ローカルオプティマイザに関する限り、リモートオブジェクトは1つだけであり、そこからデータを取得し、リモートデータベースが結合を実行します。

リモートDBに移動して、そこのテーブルでINSERTを実行するとどうなりますか?

于 2009-12-08T21:34:50.430 に答える
1

これは、OracleによるDBリンクを介した結合の処理のバグです。INSERTとSELECTを使用しない単純な状況があります。クエリをリモートで実行すると重複する行が表示されますが、ローカルで実行すると重複しません。クエリ間の唯一の違いは、リモートクエリのテーブルに追加される「@...」です。Oracle SQL Developer 3.0を使用して、10.2データベースから9iデータベースにクエリを実行しています。

これは、合計1000を超える列を持つテーブルを結合できないOracleのバグよりもさらに愚かです。これは、ERPシステムにクエリを実行するときに非常に簡単に実行できます。いいえ、エラーメッセージは、列が多すぎるテーブルに関するものではありません。

ANSI構文を使用してLOBロケーターを含むテーブルのクエリを禁止する他のOracleデータベースのバグとほぼ同じくらい愚かです。Oracle構文のみが機能します!

于 2011-11-15T23:12:14.980 に答える
0

実行しているクエリの計画を立てて、そこでCARTESIANJOINを探すことをお勧めします。これは、行の重複を引き起こしている欠落状態を示している可能性があります。

于 2009-12-09T00:34:57.593 に答える
0

テーブルに関連する他の何かからの副作用を経験しているのではないかと思わずにはいられません。データを操作している可能性のあるトリガーはありますか?

于 2009-12-08T17:33:41.080 に答える
0

私にはいくつかの選択肢があります。

  1. あなたが見る重複はすでに宛先テーブルにありましたか?

  2. Selectで、挿入先のテーブル(?)を参照している場合、Insertは結合された中でSelectと相互作用しています。

    挿入...選択...から...

複製を作成するような方法(デカルト積?)

于 2009-12-08T17:18:52.983 に答える
0

元のテーブルに重複がないことをどのように判断しましたか?

他の人が指摘しているように、これはこの奇妙な行動の最も簡単な説明のようです。

于 2009-12-08T19:26:06.347 に答える
0

よく確認してくださいJOIN。個々のテーブルに重複がない可能性がありますが、結合が指定されていないと、不注意が発生CROSS JOINし、多重度が原因で結果セットに重複が生じ、挿入されると、宛先テーブルの一意性制約に違反する可能性があります。

この場合、私が行うことは、ビューまたはCTEにクエリをネストし、SELECT:から直接重複を検出しようとすることです。

WITH resultset AS (
    -- blah, blah
)
SELECT a, b, c, COUNT(*)
FROM resultset
GROUP BY a, b, c
HAVING COUNT(*) > 1
于 2009-12-08T21:41:15.750 に答える
0

AS @Popは、挿入の実行時にSQLPlusでログインとは異なるログインを使用している場合に、この動作が発生する可能性があることをすでに示唆しています。(つまり、他のログインに同じ名前のテーブル/ビュー/シノニムがある場合)

于 2009-12-09T09:02:59.933 に答える